cantango 0.8.9.5 → 0.9.3.2

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