acl9 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,17 @@
1
+ h2. 0.12.0 (04-Jan-2010)
2
+
3
+ An anniversary release of fixes and hacks, introduced by venerable users of the plugin.
4
+
5
+ * Allow for inheritance of subject (Jeff Jaco)
6
+ * Renamed "Object" module in extensions, since it caused some breakage inside activesupport
7
+ (invisiblelama).
8
+ * @show_to@ helper for usage in views (Antono Vasiljev)
9
+ * @:association_name@ config option, now you can change Subject#role_objects to whatever
10
+ you want (Jeff Tucker).
11
+ * Fix bug when Subject#id is a string, e.g. UUID (Julien Bachmann)
12
+ * Bug with action blocks when using anonymous and another role (Franck)
13
+
14
+
1
15
  h2. 0.11.0 (16-Sep-2009)
2
16
 
3
17
  * :protect_global_roles
@@ -51,12 +51,12 @@ If you have questions, please post to the
51
51
 
52
52
  h1. Installation
53
53
 
54
- Acl9 can be installed as a gem from "GitHub":http://github.com.
54
+ Acl9 can be installed as a gem from "gemcutter":http://gemcutter.org.
55
55
 
56
56
  Add the following line to your @config/environment.rb@:
57
57
 
58
58
  <pre><code>
59
- config.gem "be9-acl9", :source => "http://gems.github.com", :lib => "acl9"
59
+ config.gem "acl9", :source => "http://gemcutter.org", :lib => "acl9"
60
60
  </pre></code>
61
61
 
62
62
  Then run @rake gems:install@ (with possible @rake gems:unpack@ thereafter) and you're done!
@@ -145,11 +145,10 @@ The structure of @roles@ table is as follows:
145
145
 
146
146
  <pre><code>
147
147
  create_table "roles", :force => true do |t|
148
- t.string "name", :limit => 40
149
- t.string "authorizable_type", :limit => 40
150
- t.integer "authorizable_id"
151
- t.datetime "created_at"
152
- t.datetime "updated_at"
148
+ t.string :name, :limit => 40
149
+ t.string :authorizable_type, :limit => 40
150
+ t.integer :authorizable_id
151
+ t.timestamps
153
152
  end
154
153
  </code></pre>
155
154
 
@@ -168,10 +167,9 @@ there should be a join table:
168
167
 
169
168
  <pre><code>
170
169
  create_table "roles_users", :id => false, :force => true do |t|
171
- t.integer "user_id"
172
- t.integer "role_id"
173
- t.datetime "created_at"
174
- t.datetime "updated_at"
170
+ t.references :user
171
+ t.references :role
172
+ t.timestamps
175
173
  end
176
174
  </code></pre>
177
175
 
@@ -280,18 +278,16 @@ Note that you'll need to change your database structure appropriately:
280
278
 
281
279
  <pre><code>
282
280
  create_table "account_roles", :force => true do |t|
283
- t.string "name", :limit => 40
284
- t.string "authorizable_type", :limit => 40
285
- t.integer "authorizable_id"
286
- t.datetime "created_at"
287
- t.datetime "updated_at"
281
+ t.string :name, :limit => 40
282
+ t.string :authorizable_type, :limit => 40
283
+ t.integer :authorizable_id
284
+ t.timestamps
288
285
  end
289
286
 
290
287
  create_table "account_roles_accounts", :id => false, :force => true do |t|
291
- t.integer "account_id"
292
- t.integer "account_role_id"
293
- t.datetime "created_at"
294
- t.datetime "updated_at"
288
+ t.references :account
289
+ t.references :account_role
290
+ t.timestamps
295
291
  end
296
292
  </code></pre>
297
293
 
@@ -885,4 +881,23 @@ An imaginary view:
885
881
  <% end %>
886
882
  </code></pre>
887
883
 
888
- Copyright (c) 2009 Oleg Dashevskii, released under the MIT license.
884
+ h2. show_to in your views
885
+
886
+ @show_to@ is predefined helper for your views:
887
+
888
+ <pre><code>
889
+ <% show_to :admin, :supervisor do %>
890
+ <%= link_to 'destroy', destroy_path %>
891
+ <% end %>
892
+ </code></pre>
893
+
894
+ or even
895
+
896
+ <pre><code>
897
+ <% show_to :prince, :of => :persia do %>
898
+ <%= link_to 'Princess', princess_path %>
899
+ <% end %>
900
+ </code></pre>
901
+
902
+
903
+ Copyright (c) 2009, 2010 Oleg Dashevskii, released under the MIT license.
@@ -1,4 +1,5 @@
1
1
  ---
2
- :minor: 11
2
+ :build:
3
+ :minor: 12
3
4
  :patch: 0
4
5
  :major: 0
@@ -3,6 +3,7 @@ module Acl9
3
3
  :default_role_class_name => 'Role',
4
4
  :default_subject_class_name => 'User',
5
5
  :default_subject_method => :current_user,
6
+ :default_association_name => :role_objects,
6
7
  :protect_global_roles => false,
7
8
  }
8
9
 
@@ -142,7 +142,8 @@ module Acl9
142
142
  end
143
143
 
144
144
  def _either_of(exprs)
145
- exprs.map { |expr| "(#{expr})" }.join(' || ')
145
+ clause = exprs.map { |expr| "(#{expr})" }.join(' || ')
146
+ return "(#{clause})"
146
147
  end
147
148
 
148
149
  def _add_rule(what, condition)
@@ -14,6 +14,29 @@ module Acl9
14
14
  generator.acl_block!(&block)
15
15
  generator.install_on(self, opts)
16
16
  end
17
+
18
+ end
19
+
20
+ # Usage:
21
+ #
22
+ # <% show_to(:owner, :supervisor, :of => :account) do -%>
23
+ # <%= 'hello' %>
24
+ # <%- end -%>
25
+ #
26
+ def show_to(*args, &block)
27
+ user = eval(Acl9.config[:default_subject_method].to_s)
28
+ return '' if user.nil?
29
+
30
+ has_any = false
31
+
32
+ if args.last.is_a?(Hash)
33
+ an_obj = args.pop.values.first
34
+ has_any = args.detect { |role| user.has_role?(role, an_obj) }
35
+ else
36
+ has_any = args.detect { |role| user.has_role?(role) }
37
+ end
38
+
39
+ has_any ? yield(:block) : ''
17
40
  end
18
41
  end
19
42
  end
@@ -1,5 +1,5 @@
1
- require File.join(File.dirname(__FILE__), 'model_extensions', 'subject')
2
- require File.join(File.dirname(__FILE__), 'model_extensions', 'object')
1
+ require File.join(File.dirname(__FILE__), 'model_extensions', 'for_subject')
2
+ require File.join(File.dirname(__FILE__), 'model_extensions', 'for_object')
3
3
 
4
4
  module Acl9
5
5
  module ModelExtensions #:nodoc:
@@ -16,6 +16,8 @@ module Acl9
16
16
  # Class name of the role class (e.g. 'AccountRole')
17
17
  # @option options [String] :join_table_name (Acl9::config[:default_join_table_name])
18
18
  # Join table name (e.g. 'accounts_account_roles')
19
+ # @option options [String] :association_name (Acl9::config[:default_association_name])
20
+ # Association name (e.g. ':roles')
19
21
  # @example
20
22
  # class User < ActiveRecord::Base
21
23
  # acts_as_authorization_subject
@@ -31,17 +33,21 @@ module Acl9
31
33
  # @see Acl9::ModelExtensions::Subject
32
34
  #
33
35
  def acts_as_authorization_subject(options = {})
36
+ assoc = options[:association_name] || Acl9::config[:default_association_name]
34
37
  role = options[:role_class_name] || Acl9::config[:default_role_class_name]
35
38
  join_table = options[:join_table_name] || Acl9::config[:default_join_table_name] ||
36
39
  join_table_name(undecorated_table_name(self.to_s), undecorated_table_name(role))
37
40
 
38
- has_and_belongs_to_many :role_objects, :class_name => role, :join_table => join_table
41
+ has_and_belongs_to_many assoc, :class_name => role, :join_table => join_table
42
+
43
+ cattr_accessor :_auth_role_class_name, :_auth_subject_class_name,
44
+ :_auth_role_assoc_name
39
45
 
40
- cattr_accessor :_auth_role_class_name, :_auth_subject_class_name
41
46
  self._auth_role_class_name = role
42
47
  self._auth_subject_class_name = self.to_s
48
+ self._auth_role_assoc_name = assoc
43
49
 
44
- include Acl9::ModelExtensions::Subject
50
+ include Acl9::ModelExtensions::ForSubject
45
51
  end
46
52
 
47
53
  # Add role query and set methods to the class (making it an auth object class).
@@ -81,7 +87,7 @@ module Acl9
81
87
 
82
88
  sql_where = <<-'EOS'
83
89
  WHERE authorizable_type = '#{self.class.base_class.to_s}'
84
- AND authorizable_id = #{id}
90
+ AND authorizable_id = #{column_for_attribute(self.class.primary_key).text? ? "'#{id}'": id}
85
91
  EOS
86
92
 
87
93
  has_many :accepted_roles, :as => :authorizable, :class_name => role, :dependent => :destroy
@@ -91,7 +97,7 @@ module Acl9
91
97
  :counter_sql => ("SELECT COUNT(DISTINCT #{subj_table}.id)" + sql_tables + sql_where),
92
98
  :readonly => true
93
99
 
94
- include Acl9::ModelExtensions::Object
100
+ include Acl9::ModelExtensions::ForObject
95
101
  end
96
102
 
97
103
  # Make a class an auth role class.
@@ -1,6 +1,6 @@
1
1
  module Acl9
2
2
  module ModelExtensions
3
- module Object
3
+ module ForObject
4
4
  ##
5
5
  # Role check.
6
6
  #
@@ -1,6 +1,6 @@
1
1
  module Acl9
2
2
  module ModelExtensions
3
- module Subject
3
+ module ForSubject
4
4
  ##
5
5
  # Role check.
6
6
  #
@@ -164,12 +164,21 @@ module Acl9
164
164
  role.destroy if role.send(self._auth_subject_class_name.demodulize.tableize).empty?
165
165
  end
166
166
  end
167
-
167
+
168
168
  protected
169
169
 
170
170
  def _auth_role_class
171
171
  self.class._auth_role_class_name.constantize
172
172
  end
173
+
174
+ def _auth_role_assoc
175
+ self.class._auth_role_assoc_name
176
+ end
177
+
178
+ def role_objects
179
+ send(self._auth_role_assoc)
180
+ end
181
+
173
182
  end
174
183
  end
175
184
  end
@@ -753,6 +753,43 @@ class DslBaseTest < Test::Unit::TestCase
753
753
  permit_some(list, @user2, %w(show index delete destroy))
754
754
  permit_some(list, @user3, %w(show index delete destroy), :object => @foo)
755
755
  end
756
+
757
+ it "should work with anonymous" do
758
+ @user << :superadmin
759
+
760
+ list = acl do
761
+ allow :superadmin
762
+
763
+ action :index, :show do
764
+ allow anonymous
765
+ end
766
+ end
767
+
768
+ @all_actions = %w(show index edit update delete destroy)
769
+
770
+ permit_some(list, @user, @all_actions)
771
+ permit_some(list, nil, %w(index show))
772
+ end
773
+
774
+ it "should work with anonymous and other role inside" do
775
+ @user << :superadmin
776
+ @user2 << :member
777
+
778
+ list = acl do
779
+ allow :superadmin
780
+
781
+ action :index, :show do
782
+ allow anonymous
783
+ allow :member
784
+ end
785
+ end
786
+
787
+ @all_actions = %w(show index edit update delete destroy)
788
+
789
+ permit_some(list, @user, @all_actions)
790
+ permit_some(list, @user2, %w(index show))
791
+ permit_some(list, nil, %w(index show))
792
+ end
756
793
  end
757
794
  end
758
795
 
@@ -17,8 +17,12 @@ class HelperTest < Test::Unit::TestCase
17
17
  user = Object.new
18
18
 
19
19
  class <<user
20
- def has_role?(role, obj=nil)
21
- role == 'hamlet'
20
+ def has_role?(role, object=nil)
21
+ if object
22
+ return (role == 'hamlet' && object.name == 'castle')
23
+ else
24
+ return role == 'hamlet'
25
+ end
22
26
  end
23
27
  end
24
28
 
@@ -29,7 +33,7 @@ class HelperTest < Test::Unit::TestCase
29
33
  module NotLoggedIn
30
34
  def current_user; nil end
31
35
  end
32
-
36
+
33
37
  module Noone
34
38
  def current_user
35
39
  user = Object.new
@@ -54,11 +58,11 @@ class HelperTest < Test::Unit::TestCase
54
58
  class Klass1 < Base
55
59
  include Hamlet
56
60
  end
57
-
61
+
58
62
  class Klass2 < Base
59
63
  include NotLoggedIn
60
64
  end
61
-
65
+
62
66
  class Klass3 < Base
63
67
  include Noone
64
68
  end
@@ -66,28 +70,65 @@ class HelperTest < Test::Unit::TestCase
66
70
  it "has :the_question method" do
67
71
  Base.new.should respond_to(:the_question)
68
72
  end
69
-
73
+
70
74
  it "role :hamlet is allowed to be" do
71
75
  k = Klass1.new
72
76
  k.action_name = 'be'
73
77
  k.the_question.should be_true
74
78
  end
75
-
79
+
76
80
  it "role :hamlet is allowed to not_be" do
77
81
  k = Klass1.new
78
82
  k.action_name = 'not_be'
79
83
  k.the_question.should be_true
80
84
  end
81
-
85
+
82
86
  it "not logged in is not allowed to be" do
83
87
  k = Klass2.new
84
88
  k.action_name = 'be'
85
89
  k.the_question.should == false
86
90
  end
87
-
91
+
88
92
  it "noone is not allowed to be" do
89
93
  k = Klass3.new
90
94
  k.action_name = 'be'
91
95
  k.the_question.should == false
92
96
  end
97
+
98
+ it "has :show_to method" do
99
+ Base.new.should respond_to(:show_to)
100
+ end
101
+
102
+ it "has :show_to hamlet 'hello hamlet' message" do
103
+ k = Klass1.new
104
+ message = 'hello hamlet'
105
+ k.show_to('hamlet') { message }.should == message
106
+ end
107
+
108
+ it "has to show message if user has hamlet role on object" do
109
+ k = Klass1.new
110
+ message = 'hello hamlet'
111
+
112
+ obj = Object.new
113
+ def obj.name; 'castle'; end
114
+
115
+ k.show_to('hamlet', :of => obj) { message }.should == message
116
+ end
117
+
118
+ it "has not to show message if user has no hamlet role on object" do
119
+ k = Klass1.new
120
+
121
+ obj = Object.new
122
+ def obj.name; 'persia'; end
123
+
124
+ k.show_to('hamlet', :of => obj) { 'hello my prince' }.should == ''
125
+ end
126
+
127
+ it "has :show_to nothing to NotLoggedIn" do
128
+ k = Klass2.new
129
+ k.action_name = 'be'
130
+ message = 'hello hamlet'
131
+ k.show_to(:hamlet) { message }.should == ''
132
+ end
133
+
93
134
  end
@@ -14,6 +14,10 @@ class RolesTest < Test::Unit::TestCase
14
14
  @user2 = User.create!
15
15
  @foo = Foo.create!
16
16
  @bar = Bar.create!
17
+ #create authorized object that has a string primary key
18
+ @uuid = Uuid.new
19
+ @uuid.uuid = "C41642EE-2780-0001-189F-17F3101B26E0"
20
+ @uuid.save
17
21
  end
18
22
 
19
23
  it "should not have any roles by default" do
@@ -221,6 +225,20 @@ class RolesTest < Test::Unit::TestCase
221
225
  Role.count.should == 0
222
226
  end
223
227
 
228
+ it "should be able to get users that have a role on a authorized object" do
229
+ @user.has_role!('owner', @bar)
230
+ @user2.has_role!('owner', @bar)
231
+
232
+ @bar.users.count.should == 2
233
+ end
234
+
235
+ it "should be able to get users that have a role on a authorized object with text primary key" do
236
+ @user.has_role!('owner', @uuid)
237
+ @user2.has_role!('owner', @uuid)
238
+
239
+ @uuid.users.count.should == 2
240
+ end
241
+
224
242
  it "should accept :symbols as role names" do
225
243
  @user.has_role! :admin
226
244
  @user.has_role! :_3133t
@@ -278,6 +296,33 @@ class RolesWithCustomClassNamesTest < Test::Unit::TestCase
278
296
  end
279
297
  end
280
298
 
299
+ class RolesWithCustomAssociationNamesTest < Test::Unit::TestCase
300
+ before do
301
+ DifferentAssociationNameRole.destroy_all
302
+ [DifferentAssociationNameSubject, FooBar].each { |model| model.delete_all }
303
+
304
+ @subj = DifferentAssociationNameSubject.create!
305
+ @subj2 = DifferentAssociationNameSubject.create!
306
+ @foobar = FooBar.create!
307
+ end
308
+
309
+ it "should basically work" do
310
+ lambda do
311
+ @subj.has_role!('admin')
312
+ @subj.has_role!('user', @foobar)
313
+ end.should change { DifferentAssociationNameRole.count }.from(0).to(2)
314
+
315
+ @subj.has_role?('admin').should be_true
316
+ @subj2.has_role?('admin').should be_false
317
+
318
+ @subj.has_role?(:user, @foobar).should be_true
319
+ @subj2.has_role?(:user, @foobar).should be_false
320
+
321
+ @subj.has_no_roles!
322
+ @subj2.has_no_roles!
323
+ end
324
+ end
325
+
281
326
  class UsersRolesAndSubjectsWithNamespacedClassNamesTest < Test::Unit::TestCase
282
327
  before do
283
328
  Other::Role.destroy_all
@@ -10,6 +10,11 @@ class Foo < ActiveRecord::Base
10
10
  acts_as_authorization_object
11
11
  end
12
12
 
13
+ class Uuid < ActiveRecord::Base
14
+ set_primary_key "uuid"
15
+ acts_as_authorization_object
16
+ end
17
+
13
18
  class Bar < ActiveRecord::Base
14
19
  acts_as_authorization_object
15
20
  end
@@ -26,6 +31,13 @@ class FooBar < ActiveRecord::Base
26
31
  acts_as_authorization_object :role_class_name => 'AnotherRole', :subject_class_name => "AnotherSubject"
27
32
  end
28
33
 
34
+ class DifferentAssociationNameSubject < ActiveRecord::Base
35
+ acts_as_authorization_subject :association_name => 'roles', :role_class_name => "DifferentAssociationNameRole"
36
+ end
37
+
38
+ class DifferentAssociationNameRole < ActiveRecord::Base
39
+ acts_as_authorization_role :subject_class_name => "DifferentAssociationNameSubject"
40
+ end
29
41
 
30
42
  module Other
31
43
 
@@ -44,4 +56,4 @@ module Other
44
56
  acts_as_authorization_object :role_class_name => 'Other::Role', :subject_class_name => "Other::User"
45
57
  end
46
58
 
47
- end
59
+ end
@@ -2,7 +2,7 @@ ActiveRecord::Schema.define(:version => 0) do
2
2
  create_table "roles", :force => true do |t|
3
3
  t.string "name", :limit => 40
4
4
  t.string "authorizable_type", :limit => 40
5
- t.integer "authorizable_id"
5
+ t.string "authorizable_id"
6
6
  t.datetime "created_at"
7
7
  t.datetime "updated_at"
8
8
  end
@@ -15,8 +15,17 @@ ActiveRecord::Schema.define(:version => 0) do
15
15
  t.datetime "updated_at"
16
16
  end
17
17
 
18
+ create_table "different_association_name_roles", :force => true do |t|
19
+ t.string "name", :limit => 40
20
+ t.string "authorizable_type", :limit => 40
21
+ t.integer "authorizable_id"
22
+ t.datetime "created_at"
23
+ t.datetime "updated_at"
24
+ end
25
+
18
26
  create_table "users", :force => true do |t| end
19
27
  create_table "another_subjects", :force => true do |t| end
28
+ create_table "different_association_name_subjects", :force => true do |t| end
20
29
 
21
30
  create_table "roles_users", :id => false, :force => true do |t|
22
31
  t.integer "user_id"
@@ -31,11 +40,25 @@ ActiveRecord::Schema.define(:version => 0) do
31
40
  t.datetime "created_at"
32
41
  t.datetime "updated_at"
33
42
  end
43
+
44
+ create_table "different_association_name_roles_different_association_name_subjects", :id => false, :force => true do |t|
45
+ t.integer "different_association_name_subject_id"
46
+ t.integer "different_association_name_role_id"
47
+ t.datetime "created_at"
48
+ t.datetime "updated_at"
49
+ end
50
+
34
51
  create_table "foos", :force => true do |t|
35
52
  t.datetime "created_at"
36
53
  t.datetime "updated_at"
37
54
  end
38
55
 
56
+ create_table "uuids", :id => false, :force => true do |t|
57
+ t.string "uuid"
58
+ t.datetime "created_at"
59
+ t.datetime "updated_at"
60
+ end
61
+
39
62
  create_table "bars", :force => true do |t|
40
63
  t.datetime "created_at"
41
64
  t.datetime "updated_at"
@@ -17,7 +17,7 @@ class Test::Unit::TestCase
17
17
  custom_matcher :be_false do |receiver, matcher, args|
18
18
  !receiver
19
19
  end
20
-
20
+
21
21
  custom_matcher :be_true do |receiver, matcher, args|
22
22
  !!receiver
23
23
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acl9
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - oleg dashevskii
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-10 00:00:00 +07:00
12
+ date: 2010-01-04 00:00:00 +06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -40,6 +40,7 @@ extensions: []
40
40
 
41
41
  extra_rdoc_files:
42
42
  - README.textile
43
+ - TODO
43
44
  files:
44
45
  - CHANGELOG.textile
45
46
  - MIT-LICENSE
@@ -54,8 +55,8 @@ files:
54
55
  - lib/acl9/controller_extensions/generators.rb
55
56
  - lib/acl9/helpers.rb
56
57
  - lib/acl9/model_extensions.rb
57
- - lib/acl9/model_extensions/object.rb
58
- - lib/acl9/model_extensions/subject.rb
58
+ - lib/acl9/model_extensions/for_object.rb
59
+ - lib/acl9/model_extensions/for_subject.rb
59
60
  - test/access_control_test.rb
60
61
  - test/dsl_base_test.rb
61
62
  - test/helpers_test.rb