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.
- data/README.textile +35 -7
- data/VERSION +1 -1
- data/cantango.gemspec +39 -12
- data/lib/cantango.rb +4 -3
- data/lib/cantango/ability.rb +17 -21
- data/lib/cantango/ability/cache/key.rb +32 -4
- data/lib/cantango/ability/cache/rules_cache.rb +9 -2
- data/lib/cantango/ability/cache_helpers.rb +1 -7
- data/lib/cantango/ability/engine_helpers.rb +27 -0
- data/lib/cantango/ability_executor.rb +41 -0
- data/lib/cantango/api/user/ability.rb +8 -12
- data/lib/cantango/api/user/session.rb +2 -1
- data/lib/cantango/api/user_account.rb +2 -2
- data/lib/cantango/api/user_account/ability.rb +19 -14
- data/lib/cantango/api/user_account/can.rb +8 -0
- data/lib/cantango/api/user_account/session.rb +33 -0
- data/lib/cantango/cached_ability.rb +26 -0
- data/lib/cantango/configuration.rb +3 -3
- data/lib/cantango/configuration/ability.rb +1 -0
- data/lib/cantango/configuration/candidate_registry.rb +51 -0
- data/lib/cantango/configuration/categories.rb +2 -2
- data/lib/cantango/configuration/engines.rb +7 -3
- data/lib/cantango/configuration/engines/permission.rb +5 -0
- data/lib/cantango/configuration/engines/permit.rb +1 -0
- data/lib/cantango/configuration/engines/user_ac.rb +19 -0
- data/lib/cantango/configuration/guest.rb +1 -1
- data/lib/cantango/configuration/modes.rb +21 -0
- data/lib/cantango/configuration/permits.rb +1 -1
- data/lib/cantango/configuration/role_groups.rb +1 -2
- data/lib/cantango/configuration/user_accounts.rb +1 -1
- data/lib/cantango/configuration/users.rb +1 -1
- data/lib/cantango/engine.rb +40 -0
- data/lib/cantango/helpers.rb +1 -1
- data/lib/cantango/helpers/debug.rb +9 -0
- data/lib/cantango/model.rb +6 -0
- data/lib/cantango/model/filter.rb +102 -0
- data/lib/cantango/model/scope.rb +57 -0
- data/lib/cantango/permission_engine.rb +14 -3
- data/lib/cantango/permission_engine/loader/base.rb +1 -6
- data/lib/cantango/permission_engine/loader/permissions.rb +10 -16
- data/lib/cantango/permission_engine/store.rb +1 -7
- data/lib/cantango/permission_engine/yaml_store.rb +3 -10
- data/lib/cantango/permit_engine.rb +17 -4
- data/lib/cantango/permit_engine/builder/base.rb +3 -1
- data/lib/cantango/permit_engine/executor/abstract.rb +2 -0
- data/lib/cantango/permit_engine/executor/base.rb +1 -1
- data/lib/cantango/permit_engine/factory.rb +5 -3
- data/lib/cantango/permit_engine/finder.rb +4 -6
- data/lib/cantango/permit_engine/util.rb +1 -1
- data/lib/cantango/permits/permit.rb +25 -0
- data/lib/cantango/permits/role_group_permit/builder.rb +23 -7
- data/lib/cantango/permits/role_permit.rb +1 -2
- data/lib/cantango/rails/helpers/rest_helper.rb +3 -2
- data/lib/cantango/user_ac_engine.rb +40 -0
- data/lib/cantango/user_ac_engine/executor.rb +59 -0
- data/lib/cantango/users/macros.rb +3 -0
- data/lib/cantango/users/user.rb +1 -1
- data/lib/cantango/users/user_account.rb +1 -1
- data/lib/generators/cantango/permission/permission_generator.rb +43 -0
- data/spec/active_record/migrations/008_create_permissions.rb +10 -0
- data/spec/cantango/ability_executor/cached_only_spec.rb +76 -0
- data/spec/cantango/ability_executor_spec.rb +75 -0
- data/spec/cantango/api/attributes_spec.rb +2 -1
- data/spec/cantango/api/current_user_accounts.rb +5 -1
- data/spec/cantango/api/user/ability_api_spec.rb +17 -4
- data/spec/cantango/api/user/can_api_spec.rb +9 -5
- data/spec/cantango/api/user/scope_api_spec.rb +15 -7
- data/spec/cantango/api/user_account/ability_api_spec.rb +12 -5
- data/spec/cantango/api/user_account/can_api_spec.rb +8 -4
- data/spec/cantango/cached_ability_spec.rb +0 -0
- data/spec/cantango/model/filter_spec.rb +168 -0
- data/spec/cantango/model/scope_spec.rb +107 -0
- data/spec/cantango/permission_engine/loader/permissions/{cantango_permissions_loader.rb → cantango_permissions_loader_spec.rb} +0 -0
- data/spec/cantango/permission_engine/loader/permissions/shared.rb +2 -2
- data/spec/cantango/permission_engine/yaml_store_spec.rb +0 -1
- data/spec/cantango/permit_engine/role_group_permit_spec.rb +2 -2
- data/spec/cantango/permits/permit_spec.rb +2 -2
- data/spec/cantango/rules_spec.rb +6 -6
- data/spec/cantango/user_ac_engine_spec.rb +53 -0
- data/spec/fixtures/config/cantango_permissions.yml +49 -0
- data/spec/fixtures/models/permission.rb +12 -0
- data/spec/fixtures/models/user.rb +8 -0
- data/spec/generators/cantango/permission_generator_spec.rb +44 -0
- metadata +59 -35
data/lib/cantango/engine.rb
CHANGED
@@ -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
|
data/lib/cantango/helpers.rb
CHANGED
@@ -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
|
-
|
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
|
25
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
61
|
+
def save_permissions perms
|
69
62
|
load_from_hash perms
|
70
63
|
end
|
71
64
|
|