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
@@ -17,7 +17,7 @@ module CanTango
17
17
  def disable_types *types
18
18
  @enabled_types = available_types - types.flatten
19
19
  end
20
- alias_method :disable, :disable_types
20
+ alias_method :disable, :disable_types
21
21
 
22
22
  def enable_all_types!
23
23
  @enabled_types = available_types
@@ -1,9 +1,8 @@
1
1
  module CanTango
2
2
  class Configuration
3
3
  class RoleGroups < RoleRegistry
4
-
5
4
  include Singleton
6
-
5
+
7
6
  def default_has_method
8
7
  :in_role_group?
9
8
  end
@@ -1,6 +1,6 @@
1
1
  module CanTango
2
2
  class Configuration
3
- class UserAccounts < Registry
3
+ class UserAccounts < CandidateRegistry
4
4
  include Singleton
5
5
  end
6
6
  end
@@ -1,6 +1,6 @@
1
1
  module CanTango
2
2
  class Configuration
3
- class Users < Registry
3
+ class Users < CandidateRegistry
4
4
  include Singleton
5
5
  end
6
6
  end
@@ -1,5 +1,7 @@
1
1
  module CanTango
2
2
  class Engine
3
+ include CanTango::Helpers::Debug
4
+
3
5
  attr_reader :ability
4
6
 
5
7
  def initialize ability
@@ -9,5 +11,43 @@ module CanTango
9
11
  def execute!
10
12
  # raise NotImplementedError
11
13
  end
14
+
15
+ def engine_name
16
+ raise NotImplementedError
17
+ end
18
+
19
+ protected
20
+
21
+ def valid_mode?
22
+ valid_cache_mode? || valid_no_cache_mode?
23
+ end
24
+
25
+ def valid_cache_mode?
26
+ modes.include?(:cache) && cache_mode?
27
+ end
28
+
29
+ def valid_no_cache_mode?
30
+ modes.include?(:no_cache) && !cache_mode?
31
+ end
32
+
33
+ def modes
34
+ CanTango.config.engine(engine_name.to_sym).modes
35
+ end
36
+
37
+ def cache_mode?
38
+ ability.cached?
39
+ end
40
+
41
+ def user
42
+ ability.user
43
+ end
44
+
45
+ def subject
46
+ ability.subject
47
+ end
48
+
49
+ def candidate
50
+ ability.candidate
51
+ end
12
52
  end
13
53
  end
@@ -1,5 +1,5 @@
1
1
  module CanTango
2
2
  module Helpers
3
- autoload_modules :RoleMethods
3
+ autoload_modules :RoleMethods, :Debug
4
4
  end
5
5
  end
@@ -0,0 +1,9 @@
1
+ module CanTango
2
+ module Helpers
3
+ module Debug
4
+ def debug msg
5
+ puts msg if CanTango.debug?
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module CanTango
2
+ module Model
3
+ autoload_modules :Filter, :Scope
4
+ end
5
+ end
6
+
@@ -0,0 +1,102 @@
1
+ module CanTango::Model
2
+ module Filter
3
+ def self.included(base)
4
+ base.send :include, CanTango::Api::User::Ability
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ def self.clean_meth_name meth_name
9
+ postfix = (meth_name =~ /\!$/) ? '!' : ''
10
+ postfix = (meth_name =~ /\?$/) ? '?' : postfix
11
+ postfix = "_by#{postfix}"
12
+ meth_name.to_s.sub(/[\!|\?]$/, '') + postfix
13
+ end
14
+
15
+ def self.normalize_args args
16
+ args = args.kind_of?(Symbol) ? [args] : args
17
+ args.map(&:to_s).map{|a| a == 'ARGS' ? '*args' : a}
18
+ end
19
+
20
+ module ClassMethods
21
+ def tango_filter *method_names
22
+ method_names.flatten.each do |name|
23
+ case name
24
+ when String, Symbol
25
+ case name.to_sym
26
+ when :REST, :MANAGE
27
+ tango_filter :create => :OPTS, :create! => :OPTS, :update_attributes => :OPTS, :update_attributes! => :OPTS
28
+ tango_filter :destroy, :destroy!
29
+ when :CREATE, :NEW
30
+ tango_filter :create => :OPTS, :create! => :OPTS
31
+ when :UPDATE, :EDIT
32
+ tango_filter :update_attributes => :OPTS, :update_attributes! => :OPTS
33
+ when :DELETE, :DESTROY
34
+ tango_filter :destroy, :destroy!
35
+ else
36
+ meth_name = name.to_s
37
+ method_name = CanTango::Model::Filter.clean_meth_name meth_name
38
+ define_method :"#{method_name}" do |user|
39
+ send(name) if user_ability(user).can? meth_name.to_sym, self
40
+ end
41
+ end
42
+ when Hash
43
+ base = self
44
+ name.each_pair do |meth_name, args|
45
+ norm_args = CanTango::Model::Filter.normalize_args args
46
+ args = norm_args.map{|a| a == 'OPTS' ? 'options = {}' : a}.join(',')
47
+ args_call = norm_args.map{|a| a == 'OPTS' ? 'options' : a}.join(',')
48
+
49
+ method_name = CanTango::Model::Filter.clean_meth_name meth_name
50
+
51
+ base.class_eval %{
52
+ def #{method_name} the_user, #{args}
53
+ send(:#{meth_name}, #{args_call}) if user_ability(the_user).can? :#{meth_name}, self
54
+ end
55
+ }
56
+ end
57
+ end
58
+ end
59
+ end # def
60
+
61
+ def tango_account_filter *method_names
62
+ method_names.flatten.each do |name|
63
+ case name
64
+ when String, Symbol
65
+ case name.to_sym
66
+ when :REST, :MANAGE
67
+ tango_account_filter :create => :OPTS, :create! => :OPTS, :update_attributes => :OPTS, :update_attributes! => :OPTS
68
+ tango_account_filter :destroy, :destroy!
69
+ when :CREATE, :NEW
70
+ tango_account_filter :create => :OPTS, :create! => :OPTS
71
+ when :UPDATE, :EDIT
72
+ tango_account_filter :update_attributes => :OPTS, :update_attributes! => :OPTS
73
+ when :DELETE, :DESTROY
74
+ tango_account_filter :destroy, :destroy!
75
+ else
76
+ meth_name = name.to_s
77
+ method_name = CanTango::Model::Filter.clean_meth_name meth_name
78
+ define_method :"#{method_name}" do |user|
79
+ send(name) if account_ability(user).can? meth_name.to_sym, self
80
+ end
81
+ end
82
+ when Hash
83
+ base = self
84
+ name.each_pair do |meth_name, args|
85
+ norm_args = CanTango::Model::Filter.normalize_args args
86
+ args = norm_args.map{|a| a == 'OPTS' ? 'options = {}' : a}.join(',')
87
+ args_call = norm_args.map{|a| a == 'OPTS' ? 'options' : a}.join(',')
88
+
89
+ method_name = CanTango::Model::Filter.clean_meth_name meth_name
90
+
91
+ base.class_eval %{
92
+ def #{method_name} the_user, #{args}
93
+ send(:#{meth_name}, #{args_call}) if account_ability(the_user).can? :#{meth_name}, self
94
+ end
95
+ }
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,57 @@
1
+ module CanTango::Model
2
+ module Scope
3
+ def self.included(base)
4
+ base.send :include, CanTango::Api::User::Ability
5
+ base.extend CanTango::Api::User::Ability
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ def self.rest_actions
10
+ [:read, :access, :write, :manage, :edit, :create, :delete]
11
+ end
12
+
13
+ class AllowedActions
14
+ include CanTango::Api::User::Ability
15
+
16
+
17
+ attr_reader :actions, :clazz
18
+
19
+ def initialize clazz, *actions
20
+ @clazz = clazz
21
+ @actions = actions.flatten
22
+ end
23
+
24
+ def by_user user
25
+ check user_ability(user)
26
+ end
27
+ alias_method :by, :by_user
28
+
29
+ def by_account account
30
+ check account_ability(account)
31
+ end
32
+
33
+ protected
34
+
35
+ def check ability
36
+ clazz.all.select do |obj|
37
+ actions.all? do |action|
38
+ ability.can? action.to_sym, obj
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ module ClassMethods
45
+ def allowed_to *actions
46
+ CanTango::Model::Scope::AllowedActions.new self, *actions
47
+ end
48
+
49
+ CanTango::Model::Scope.rest_actions.each do |action|
50
+ meth_name = action.to_s.sub(/e$/, '') << "able"
51
+ define_method :"#{meth_name}_by" do |user|
52
+ all.select {|obj| obj.user_ability(user).can? action.to_sym, obj }
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -9,20 +9,31 @@ module CanTango
9
9
  end
10
10
 
11
11
  def execute!
12
- puts "Permission Engine executing..." if CanTango.config.debug.on?
12
+ return if !valid?
13
+ debug "Permission Engine executing..."
13
14
  permissions.each do |permission|
14
15
  permission.evaluate! user
15
16
  end
16
17
  end
17
18
 
19
+ def engine_name
20
+ :permission
21
+ end
22
+
23
+ def valid?
24
+ return false if !valid_mode?
25
+ permissions.empty? ? invalid : true
26
+ end
27
+
18
28
  def permissions
19
29
  permission_factory.build!
20
30
  end
21
31
 
22
32
  protected
23
33
 
24
- def user
25
- ability.user
34
+ def invalid
35
+ debug "No permissions found!"
36
+ false
26
37
  end
27
38
 
28
39
  def permission_factory
@@ -4,7 +4,7 @@ module CanTango
4
4
  class Base
5
5
  attr_accessor :file_name
6
6
 
7
- def self.inherited(subclass)
7
+ def self.inherited subclass
8
8
  subclass.extend ClassMethods
9
9
  end
10
10
 
@@ -12,11 +12,6 @@ module CanTango
12
12
  raise NotImplementedError
13
13
  end
14
14
 
15
- def file_name= file
16
- raise "Couldn't find permissions file: #{file}. Either disable Permission engine or add this file." if file.nil? || !File.file?(file)
17
- @file_name = file
18
- end
19
-
20
15
  def yml_content
21
16
  YAML.load_file(file_name)
22
17
  rescue
@@ -5,36 +5,28 @@ module CanTango
5
5
  attr_accessor :permissions
6
6
 
7
7
  def initialize file_name
8
- self.file_name = file_name
8
+ @file_name = file_name
9
+
9
10
  load!
10
11
  end
11
12
 
12
13
  def load_from_hash hash
13
14
  return if hash.empty?
14
15
  hash.each do |type, groups|
16
+ permissions[type] ||= {}
17
+
18
+ next if groups.nil?
19
+
15
20
  groups.each do |group, rules|
16
- permissions[type] ||= {}
17
21
  parser.parse(group, rules) do |permission|
18
22
  permissions[type][permission.name] = permission
19
23
  end
20
24
  end
21
25
  end
22
- rescue => e
23
- raise "PermissionsLoader Error: The permissions for the file #{file_name} could not be loaded - cause was #{e}"
24
26
  end
25
27
 
26
28
  def load!
27
- return if yml_content.empty?
28
- yml_content.each do |type, groups|
29
- (permissions[type] = {} # This is for having fx empty users: section
30
- next) if groups.nil? #
31
- groups.each do |group, rules|
32
- permissions[type] ||= {}
33
- parser.parse(group, rules) do |permission|
34
- permissions[type][permission.name] = permission
35
- end
36
- end
37
- end
29
+ load_from_hash yml_content
38
30
  rescue => e
39
31
  raise "PermissionsLoader Error: The permissions for the file #{file_name} could not be loaded - cause was #{e}"
40
32
  end
@@ -54,15 +46,17 @@ module CanTango
54
46
 
55
47
  define_method(:"#{type}_compiled_permissions") do
56
48
  type_permissions = send(:"#{type}_permissions")
49
+
57
50
  return Hashie::Mash.new if !type_permissions || type_permissions.empty?
51
+
58
52
  compiled_sum = send(:"#{type}_permissions").inject({}) do |compiled_sum, (actor, permission)|
59
53
  compiled_sum.merge(permission.to_compiled_hash)
60
54
  end
55
+
61
56
  Hashie::Mash.new(compiled_sum)
62
57
  end
63
58
  end
64
59
 
65
- include ClassMethods
66
60
  end
67
61
  end
68
62
  end
@@ -14,18 +14,12 @@ module CanTango
14
14
  end
15
15
  end
16
16
 
17
- def self.create name, options = {}
18
- self.new name, options
19
- end
20
-
21
17
  def load!
22
18
  raise NotImplementedError
23
19
  end
24
20
 
25
21
  def save! permissions
26
- permissions.each do |permission|
27
- store permission
28
- end
22
+ raise NotImplementedError
29
23
  end
30
24
 
31
25
  end
@@ -12,10 +12,6 @@ module CanTango
12
12
  super
13
13
  end
14
14
 
15
- def self.create name, options = {}
16
- super
17
- end
18
-
19
15
  def load!
20
16
  loader.load!
21
17
  end
@@ -32,7 +28,7 @@ module CanTango
32
28
 
33
29
  CanTango.config.permission_engine.types.each do |type|
34
30
  define_method(:"#{type}_permissions") do
35
- loader.send(:"#{type}_permissions")
31
+ loader.send(:"#{type}_permissions") || {}
36
32
  end
37
33
 
38
34
  define_method(:"#{type}_permissions_rules") do
@@ -51,10 +47,7 @@ module CanTango
51
47
 
52
48
  # @stanislaw: this needs revision!
53
49
 
54
- define_method(:"#{type}_rules") do
55
- #cache(":#{type}") ||
56
- send(:"#{type}_compiled_permissions")
57
- end
50
+ alias_method :"#{type}_rules", :"#{type}_compiled_permissions"
58
51
  end
59
52
 
60
53
  def save! perms = nil
@@ -65,7 +58,7 @@ module CanTango
65
58
  end
66
59
  end
67
60
 
68
- def save_permissions(perms)
61
+ def save_permissions perms
69
62
  load_from_hash perms
70
63
  end
71
64