cantango 0.8.9.5 → 0.9.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/README.textile +35 -7
  2. data/VERSION +1 -1
  3. data/cantango.gemspec +39 -12
  4. data/lib/cantango.rb +4 -3
  5. data/lib/cantango/ability.rb +17 -21
  6. data/lib/cantango/ability/cache/key.rb +32 -4
  7. data/lib/cantango/ability/cache/rules_cache.rb +9 -2
  8. data/lib/cantango/ability/cache_helpers.rb +1 -7
  9. data/lib/cantango/ability/engine_helpers.rb +27 -0
  10. data/lib/cantango/ability_executor.rb +41 -0
  11. data/lib/cantango/api/user/ability.rb +8 -12
  12. data/lib/cantango/api/user/session.rb +2 -1
  13. data/lib/cantango/api/user_account.rb +2 -2
  14. data/lib/cantango/api/user_account/ability.rb +19 -14
  15. data/lib/cantango/api/user_account/can.rb +8 -0
  16. data/lib/cantango/api/user_account/session.rb +33 -0
  17. data/lib/cantango/cached_ability.rb +26 -0
  18. data/lib/cantango/configuration.rb +3 -3
  19. data/lib/cantango/configuration/ability.rb +1 -0
  20. data/lib/cantango/configuration/candidate_registry.rb +51 -0
  21. data/lib/cantango/configuration/categories.rb +2 -2
  22. data/lib/cantango/configuration/engines.rb +7 -3
  23. data/lib/cantango/configuration/engines/permission.rb +5 -0
  24. data/lib/cantango/configuration/engines/permit.rb +1 -0
  25. data/lib/cantango/configuration/engines/user_ac.rb +19 -0
  26. data/lib/cantango/configuration/guest.rb +1 -1
  27. data/lib/cantango/configuration/modes.rb +21 -0
  28. data/lib/cantango/configuration/permits.rb +1 -1
  29. data/lib/cantango/configuration/role_groups.rb +1 -2
  30. data/lib/cantango/configuration/user_accounts.rb +1 -1
  31. data/lib/cantango/configuration/users.rb +1 -1
  32. data/lib/cantango/engine.rb +40 -0
  33. data/lib/cantango/helpers.rb +1 -1
  34. data/lib/cantango/helpers/debug.rb +9 -0
  35. data/lib/cantango/model.rb +6 -0
  36. data/lib/cantango/model/filter.rb +102 -0
  37. data/lib/cantango/model/scope.rb +57 -0
  38. data/lib/cantango/permission_engine.rb +14 -3
  39. data/lib/cantango/permission_engine/loader/base.rb +1 -6
  40. data/lib/cantango/permission_engine/loader/permissions.rb +10 -16
  41. data/lib/cantango/permission_engine/store.rb +1 -7
  42. data/lib/cantango/permission_engine/yaml_store.rb +3 -10
  43. data/lib/cantango/permit_engine.rb +17 -4
  44. data/lib/cantango/permit_engine/builder/base.rb +3 -1
  45. data/lib/cantango/permit_engine/executor/abstract.rb +2 -0
  46. data/lib/cantango/permit_engine/executor/base.rb +1 -1
  47. data/lib/cantango/permit_engine/factory.rb +5 -3
  48. data/lib/cantango/permit_engine/finder.rb +4 -6
  49. data/lib/cantango/permit_engine/util.rb +1 -1
  50. data/lib/cantango/permits/permit.rb +25 -0
  51. data/lib/cantango/permits/role_group_permit/builder.rb +23 -7
  52. data/lib/cantango/permits/role_permit.rb +1 -2
  53. data/lib/cantango/rails/helpers/rest_helper.rb +3 -2
  54. data/lib/cantango/user_ac_engine.rb +40 -0
  55. data/lib/cantango/user_ac_engine/executor.rb +59 -0
  56. data/lib/cantango/users/macros.rb +3 -0
  57. data/lib/cantango/users/user.rb +1 -1
  58. data/lib/cantango/users/user_account.rb +1 -1
  59. data/lib/generators/cantango/permission/permission_generator.rb +43 -0
  60. data/spec/active_record/migrations/008_create_permissions.rb +10 -0
  61. data/spec/cantango/ability_executor/cached_only_spec.rb +76 -0
  62. data/spec/cantango/ability_executor_spec.rb +75 -0
  63. data/spec/cantango/api/attributes_spec.rb +2 -1
  64. data/spec/cantango/api/current_user_accounts.rb +5 -1
  65. data/spec/cantango/api/user/ability_api_spec.rb +17 -4
  66. data/spec/cantango/api/user/can_api_spec.rb +9 -5
  67. data/spec/cantango/api/user/scope_api_spec.rb +15 -7
  68. data/spec/cantango/api/user_account/ability_api_spec.rb +12 -5
  69. data/spec/cantango/api/user_account/can_api_spec.rb +8 -4
  70. data/spec/cantango/cached_ability_spec.rb +0 -0
  71. data/spec/cantango/model/filter_spec.rb +168 -0
  72. data/spec/cantango/model/scope_spec.rb +107 -0
  73. data/spec/cantango/permission_engine/loader/permissions/{cantango_permissions_loader.rb → cantango_permissions_loader_spec.rb} +0 -0
  74. data/spec/cantango/permission_engine/loader/permissions/shared.rb +2 -2
  75. data/spec/cantango/permission_engine/yaml_store_spec.rb +0 -1
  76. data/spec/cantango/permit_engine/role_group_permit_spec.rb +2 -2
  77. data/spec/cantango/permits/permit_spec.rb +2 -2
  78. data/spec/cantango/rules_spec.rb +6 -6
  79. data/spec/cantango/user_ac_engine_spec.rb +53 -0
  80. data/spec/fixtures/config/cantango_permissions.yml +49 -0
  81. data/spec/fixtures/models/permission.rb +12 -0
  82. data/spec/fixtures/models/user.rb +8 -0
  83. data/spec/generators/cantango/permission_generator_spec.rb +44 -0
  84. metadata +59 -35
@@ -0,0 +1,41 @@
1
+ module CanTango
2
+ class AbilityExecutor < CanTango::Ability
3
+ attr_reader :rules
4
+
5
+ def initialize candidate, options = {}
6
+ raise "Candidate must be something!" if !candidate
7
+ @candidate, @options = [candidate, options]
8
+ @rules = cached_rules + non_cached_rules
9
+ end
10
+
11
+ def cached_rules
12
+ cache_mode? ? cached_ability.send(:rules) : []
13
+ end
14
+
15
+ def non_cached_rules
16
+ no_cache_mode? ? non_cached_ability.send(:rules) : []
17
+ end
18
+
19
+ def cached_ability
20
+ CanTango::CachedAbility.new candidate, options
21
+ end
22
+
23
+ def non_cached_ability
24
+ CanTango::Ability.new candidate, options
25
+ end
26
+
27
+ protected
28
+
29
+ def no_cache_mode?
30
+ modes.include?(:no_cache)
31
+ end
32
+
33
+ def cache_mode?
34
+ modes.include?(:cache)
35
+ end
36
+
37
+ def modes
38
+ CanTango.config.ability.modes
39
+ end
40
+ end
41
+ end
@@ -17,24 +17,20 @@ module CanTango
17
17
  def get_ability_user user_type
18
18
  user_meth = :"current_#{user_type}"
19
19
  return AbilityUser.guest if !respond_to?(user_meth)
20
+ AbilityUser.resolve_user(send user_meth)
21
+ end
20
22
 
21
- user = send user_meth
23
+ module AbilityUser
22
24
  # test if current_xxx actually returns an account and not a user instance!
23
25
  # if so call the #user method on the account
24
- user = AbilityUser.resolve_user(user)
25
- # return guest user if user is nil
26
- user ? user : AbilityUser.guest
27
- end
28
-
29
- module AbilityUser
30
26
  def self.resolve_user obj
31
- return obj if AbilityUser.is_a_user?(obj)
32
- return obj.send(:user) if obj.respond_to? :user
33
- raise "no user object could be resolved via #{obj}. Please define a #user method for #{obj.class}"
27
+ return obj if is_user?(obj)
28
+ return resolve_user(obj.send(:user)) if obj.respond_to? :user
29
+ guest
34
30
  end
35
31
 
36
- def self.is_a_user? user
37
- ::CanTango.config.users.registered.include?(user.class.to_s.underscore.to_sym)
32
+ def self.is_user? user
33
+ ::CanTango.config.users.registered_class? user.class
38
34
  end
39
35
 
40
36
  def self.guest
@@ -22,7 +22,8 @@ module CanTango
22
22
  def any_user *types
23
23
  types = types.flatten.select_labels.map(&:to_sym)
24
24
  c_user = ::CanTango.config.users.registered.each do |user|
25
- send(:"current_#{user}") if respond_to?(:"current_#{user}") && (types.empty? || types.include?(user))
25
+ meth = :"current_#{user}"
26
+ send(meth) if respond_to?(meth) && (types.empty? || types.include?(user))
26
27
  end.compact.first
27
28
  c_user || guest_user
28
29
  end
@@ -1,11 +1,11 @@
1
1
  module CanTango
2
2
  module Api
3
3
  module UserAccount
4
- autoload_modules :Ability, :Can, :Scope
4
+ autoload_modules :Ability, :Can, :Scope, :Session
5
5
 
6
6
  module All
7
7
  def self.included base
8
- [:Ability, :Can, :Scope].each do |api|
8
+ [:Ability, :Can, :Scope, :Session].each do |api|
9
9
  base.send :include, clazz(api)
10
10
  end
11
11
  end
@@ -5,30 +5,35 @@ module CanTango
5
5
  def user_account_ability user_account, options = {}
6
6
  @current_ability ||= create_ability(user_account, ability_options.merge(options))
7
7
  end
8
+ alias_method :account_ability, :user_account_ability
8
9
 
9
10
  def current_account_ability user_type = :user
10
- account_meth = :"current_#{user_type}_account"
11
- return guest_user_account if !respond_to?(account_meth)
12
-
13
- user_account = send(account_meth)
14
- return guest_user_account if !user_account
15
-
16
- user_account_ability user_account
11
+ user_account_ability get_ability_user_account
17
12
  end
18
13
 
19
14
  protected
20
15
 
21
16
  include CanTango::Api::Common
22
17
 
23
- def get_ability_user_acount user_type
24
- user_account_meth = :"current_#{user_type}_account"
25
- return AbilityAccount.guest if !respond_to?(user_account_meth)
26
-
27
- user_account = send user_account_meth
28
- user_account ? user_account : AbilityAccount.guest
29
- end
18
+ def get_ability_user_account user_type = :user
19
+ account_meth = :"current_#{user_type}_account"
20
+ return AbilityAccount.guest if !respond_to?(account_meth)
21
+ AbilityAccount.resolve_account(send account_meth)
22
+ end
30
23
 
31
24
  module AbilityAccount
25
+ # test if current_xxx actually returns an account and not a user instance!
26
+ # if so call the #account method on the user
27
+ def self.resolve_account obj
28
+ return obj if AbilityAccount.is_account?(obj)
29
+ return resolve_account(obj.send(:account)) if obj.respond_to?(:account)
30
+ guest
31
+ end
32
+
33
+ def self.is_account? account
34
+ ::CanTango.config.user_accounts.registered_class? account.class
35
+ end
36
+
32
37
  def self.guest
33
38
  account = CanTango.config.guest.account
34
39
 
@@ -9,6 +9,14 @@ module CanTango
9
9
  # end
10
10
  def self.included(base)
11
11
  ::CanTango.config.user_accounts.registered.each do |account|
12
+
13
+ # by default alias call to current_xxx_account to current_xxx (devise user method) unless already defined!
14
+ unless base.methods.include? :"current_#{account}_account"
15
+ define_method :"current_#{account}_account" do
16
+ send :"current_#{account}"
17
+ end
18
+ end
19
+
12
20
  base.class_eval %{
13
21
  def #{account}_account_can? *args
14
22
  current_account_ability(:#{account}).can?(*args)
@@ -0,0 +1,33 @@
1
+ module CanTango
2
+ module Api
3
+ module UserAccount
4
+ module Session
5
+ def self.included(base)
6
+ ::CanTango.config.user_accounts.registered.each do |type|
7
+ base.class_eval %{
8
+ def session_#{type}_account
9
+ current_#{type}_account if respond_to? :current_#{type}_account
10
+ guest_account
11
+ end
12
+ }
13
+ end
14
+ end
15
+
16
+ # give me any logged in user or the guest user
17
+ def any_account *types
18
+ types = types.flatten.select_labels.map(&:to_sym)
19
+ c_account = ::CanTango.config.user_accounts.registered.each do |type|
20
+ meth = :"current_#{type}_account"
21
+ send(meth) if respond_to?(meth) && (types.empty? || types.include?(user))
22
+ end.compact.first
23
+ c_account || guest_account
24
+ end
25
+
26
+ def guest_account
27
+ CanTango.config.guest.account
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,26 @@
1
+ module CanTango
2
+ class CachedAbility < Ability
3
+ # Equivalent to a CanCan Ability#initialize call
4
+ # which executes all the permission logic
5
+ def initialize candidate, options = {}
6
+ raise "Candidate must be something!" if !candidate
7
+ @candidate, @options = candidate, options
8
+
9
+ return if cached_rules?
10
+
11
+ clear_rules!
12
+ permit_rules
13
+
14
+ execute_engines! if engines_on?
15
+ cache_rules!
16
+ end
17
+
18
+ def cached?
19
+ true
20
+ end
21
+
22
+ def permit_rules
23
+ end
24
+ end
25
+ end
26
+
@@ -6,15 +6,15 @@ module CanTango
6
6
  autoload_modules :Categories
7
7
  autoload_modules :Models, :Engines, :Ability
8
8
  autoload_modules :User, :Guest, :UserAccount
9
- autoload_modules :Roles, :RoleGroups, :Registry, :RoleRegistry, :HashRegistry, :PermitRegistry, :Factory
10
- autoload_modules :SpecialPermits, :Autoload, :Adapters, :Permits, :Debug
9
+ autoload_modules :Roles, :RoleGroups, :Registry, :RoleRegistry, :HashRegistry, :PermitRegistry, :CandidateRegistry, :Factory
10
+ autoload_modules :SpecialPermits, :Autoload, :Adapters, :Permits, :Debug, :Modes
11
11
  autoload_modules :Users, :UserAccounts
12
12
 
13
13
  include Singleton
14
14
 
15
15
  def ability
16
16
  @ability ||= conf::Ability.instance
17
- @ability.default_class ||= CanTango::Ability
17
+ @ability.default_class ||= CanTango::AbilityExecutor
18
18
  @ability
19
19
  end
20
20
 
@@ -5,6 +5,7 @@ module CanTango
5
5
  include ClassExt
6
6
 
7
7
  include CanTango::Configuration::Factory
8
+ include CanTango::Configuration::Modes
8
9
  end
9
10
  end
10
11
  end
@@ -0,0 +1,51 @@
1
+ require 'singleton'
2
+ require 'sugar-high/kind_of'
3
+
4
+ module CanTango
5
+ class Configuration
6
+ class CandidateRegistry
7
+ def register name, clazz
8
+ raise "first arg must be a label" if !name.kind_of_label?
9
+ raise "second arg must be a Class" if !clazz.kind_of? Class
10
+ name_registry.register name.to_sym
11
+ class_registry.register clazz
12
+ end
13
+
14
+ def registered
15
+ name_registry.registered
16
+ end
17
+
18
+ def registered_classes
19
+ class_registry.registered
20
+ end
21
+
22
+ def registered? name
23
+ name_registry.registered? name
24
+ end
25
+
26
+ def registered_class? name
27
+ class_registry.registered? name
28
+ end
29
+
30
+ def name_registry
31
+ NameRegistry.instance
32
+ end
33
+
34
+ def class_registry
35
+ ClassRegistry.instance
36
+ end
37
+
38
+ class NameRegistry < Registry
39
+ include Singleton
40
+ end
41
+
42
+ class ClassRegistry < Registry
43
+ include Singleton
44
+
45
+ def types
46
+ [Class]
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,7 +1,7 @@
1
1
  module CanTango
2
2
  class Configuration
3
3
  class Categories < HashRegistry
4
-
4
+
5
5
  include Singleton
6
6
 
7
7
  def [] label
@@ -9,7 +9,7 @@ module CanTango
9
9
  raise "Category '#{label}' either not exists or invalid!" if !models.kind_of?(Array)
10
10
  models
11
11
  end
12
-
12
+
13
13
  def category label, &block
14
14
  cat = Category.new self[label]
15
15
  yield cat if block
@@ -3,7 +3,7 @@ require 'singleton'
3
3
  module CanTango
4
4
  class Configuration
5
5
  class Engines
6
- autoload_modules :Permission, :Permit, :Cache, :Store, :Engine
6
+ autoload_modules :Permission, :Permit, :UserAc, :Cache, :Store, :Engine
7
7
 
8
8
  include Singleton
9
9
  include Enumerable
@@ -29,7 +29,7 @@ module CanTango
29
29
  end
30
30
 
31
31
  def default_register
32
- {:permit => CanTango::PermitEngine, :permission => CanTango::PermissionEngine }
32
+ {:permit => CanTango::PermitEngine, :permission => CanTango::PermissionEngine, :user_ac => CanTango::UserAcEngine }
33
33
  end
34
34
 
35
35
  # defines the order of execution of engine in ability
@@ -60,7 +60,7 @@ module CanTango
60
60
  end
61
61
 
62
62
  def self.default_available
63
- [:cache, :permission , :permit]
63
+ [:cache, :permission , :permit, :user_ac]
64
64
  end
65
65
 
66
66
  def default_available
@@ -79,6 +79,10 @@ module CanTango
79
79
  available.each {|engine| send(engine).set state }
80
80
  end
81
81
 
82
+ def any? state
83
+ available.any? {|engine| send(engine).send(:"#{state}?") if respond_to?(engine) }
84
+ end
85
+
82
86
  def clear!
83
87
  each {|engine| engine.reset! }
84
88
  @registered = nil
@@ -5,6 +5,11 @@ module CanTango
5
5
  class Engines
6
6
  class Permission < Engine
7
7
  include Singleton
8
+ include CanTango::Configuration::Modes
9
+
10
+ def modes
11
+ @modes ||= [:cache]
12
+ end
8
13
 
9
14
  def store &block
10
15
  @store ||= ns::Store.new
@@ -5,6 +5,7 @@ module CanTango
5
5
  class Engines
6
6
  class Permit < Engine
7
7
  include Singleton
8
+ include CanTango::Configuration::Modes
8
9
 
9
10
  def on?
10
11
  @state ||= :on
@@ -0,0 +1,19 @@
1
+ require 'singleton'
2
+
3
+ module CanTango
4
+ class Configuration
5
+ class Engines
6
+ class UserAc < Engine
7
+ include Singleton
8
+ include CanTango::Configuration::Modes
9
+
10
+ def modes
11
+ @modes ||= [:no_cache]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+
19
+
@@ -19,7 +19,7 @@ module CanTango
19
19
  return (@account || guest_account) if !account && !block
20
20
  @account = account || yield
21
21
  end
22
-
22
+ alias_method :user_account, :account
23
23
  alias_method :account=, :account
24
24
 
25
25
  def default_user?
@@ -0,0 +1,21 @@
1
+ module CanTango
2
+ class Configuration
3
+ module Modes
4
+ def modes
5
+ @modes ||= [:cache, :no_cache]
6
+ end
7
+
8
+ def mode= mode_name
9
+ mode_name = mode_name.to_sym
10
+ raise ArgumentException, "Not a valid mode name" if !valid_mode_names.include? mode_name
11
+ @modes = (mode_name == :both) ? [:cache, :no_cache] : [mode_name]
12
+ end
13
+
14
+ private
15
+
16
+ def valid_mode_names
17
+ [:cache, :no_cache, :both]
18
+ end
19
+ end
20
+ end
21
+ end