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
@@ -8,10 +8,9 @@ module CanTango
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def execute!
|
11
|
-
if
|
12
|
-
|
13
|
-
|
14
|
-
end
|
11
|
+
return if !valid?
|
12
|
+
debug "Permit Engine executing..."
|
13
|
+
|
15
14
|
# CanTango.config.permits.clear_executed! # should there be an option clear before each execution?
|
16
15
|
permits.each do |permit|
|
17
16
|
CanTango.config.permits.was_executed(permit, ability) if CanTango.config.debug.on?
|
@@ -19,6 +18,15 @@ module CanTango
|
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|
21
|
+
def engine_name
|
22
|
+
:permit
|
23
|
+
end
|
24
|
+
|
25
|
+
def valid?
|
26
|
+
return false if !valid_mode?
|
27
|
+
permits.empty? ? invalid : true
|
28
|
+
end
|
29
|
+
|
22
30
|
# by default, only execute permits for which the user
|
23
31
|
# has a role or a role group
|
24
32
|
# also execute any permit marked as special
|
@@ -32,6 +40,11 @@ module CanTango
|
|
32
40
|
|
33
41
|
protected
|
34
42
|
|
43
|
+
def invalid
|
44
|
+
debug "No permits found!"
|
45
|
+
false
|
46
|
+
end
|
47
|
+
|
35
48
|
def permit_factory
|
36
49
|
@permit_factory ||= CanTango::PermitEngine::Factory.new ability
|
37
50
|
end
|
@@ -4,6 +4,8 @@ module CanTango
|
|
4
4
|
class CreatePermitError < StandardError; end;
|
5
5
|
|
6
6
|
class Base
|
7
|
+
include CanTango::Helpers::Debug
|
8
|
+
|
7
9
|
attr_accessor :ability
|
8
10
|
|
9
11
|
# creates the factory for the ability
|
@@ -37,7 +39,7 @@ module CanTango
|
|
37
39
|
end
|
38
40
|
|
39
41
|
def permit_clazz name
|
40
|
-
|
42
|
+
debug "Permit Finder: #{finder}"
|
41
43
|
finder.new(subject, name).get_permit
|
42
44
|
end
|
43
45
|
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module CanTango
|
2
2
|
class PermitEngine < Engine
|
3
3
|
class Factory
|
4
|
+
include CanTango::Helpers::Debug
|
5
|
+
|
4
6
|
attr_accessor :ability
|
5
7
|
|
6
8
|
# creates the factory for the ability
|
@@ -11,15 +13,15 @@ module CanTango
|
|
11
13
|
end
|
12
14
|
|
13
15
|
def build!
|
14
|
-
|
16
|
+
debug "PermitEngine Factory: No permits could be built" if permits.empty?
|
15
17
|
permits
|
16
18
|
end
|
17
19
|
|
18
20
|
def permits
|
19
21
|
@permits ||= builders.inject([]) do |permits, builder|
|
20
|
-
|
22
|
+
debug "++ Permit Builder: #{builder_class builder}"
|
21
23
|
built_permits = permits_built_with(builder)
|
22
|
-
|
24
|
+
debug "== Permits built: #{built_permits.size}"
|
23
25
|
permits = permits + built_permits if built_permits
|
24
26
|
end.flatten
|
25
27
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module CanTango
|
2
2
|
class PermitEngine < Engine
|
3
3
|
class Finder
|
4
|
+
include CanTango::Helpers::Debug
|
5
|
+
|
4
6
|
# This class is used to find the right permit, possible scoped for a specific user account
|
5
7
|
attr_reader :user_account, :name
|
6
8
|
|
@@ -44,12 +46,8 @@ module CanTango
|
|
44
46
|
|
45
47
|
def permit
|
46
48
|
found = registered_permits.registered_for type, name
|
47
|
-
|
48
|
-
found
|
49
|
-
end
|
50
|
-
|
51
|
-
def debug_msg msg
|
52
|
-
puts msg if CanTango.debug?
|
49
|
+
debug permit_msg(found)
|
50
|
+
found
|
53
51
|
end
|
54
52
|
|
55
53
|
def permit_msg found
|
@@ -30,6 +30,10 @@ module CanTango
|
|
30
30
|
clazz.name.gsub(/::.*/,'').gsub(/(.*)Permits/, '\1').underscore.to_sym
|
31
31
|
end
|
32
32
|
|
33
|
+
def cached?
|
34
|
+
ability.cached?
|
35
|
+
end
|
36
|
+
|
33
37
|
def permit_type
|
34
38
|
self.class.type
|
35
39
|
end
|
@@ -119,11 +123,32 @@ module CanTango
|
|
119
123
|
# or if subclassing another Permit than Permit::Base
|
120
124
|
#
|
121
125
|
def permit?
|
126
|
+
cached? ? cached_rules : non_cached_rules
|
127
|
+
run_rule_methods
|
128
|
+
end
|
129
|
+
|
130
|
+
def run_rule_methods
|
122
131
|
static_rules
|
123
132
|
permit_rules
|
124
133
|
dynamic_rules
|
125
134
|
end
|
126
135
|
|
136
|
+
def non_cached_rules
|
137
|
+
include_non_cached if defined?(self.class::NonCached)
|
138
|
+
end
|
139
|
+
|
140
|
+
def cached_rules
|
141
|
+
include_cached if defined?(self.class::Cached)
|
142
|
+
end
|
143
|
+
|
144
|
+
def include_non_cached
|
145
|
+
self.class.send :include, self.class::NonCached
|
146
|
+
end
|
147
|
+
|
148
|
+
def include_cached
|
149
|
+
self.class.send :include, self.class::Cached
|
150
|
+
end
|
151
|
+
|
127
152
|
def licenses *names
|
128
153
|
names.to_strings.each do |name|
|
129
154
|
try_license name
|
@@ -8,17 +8,17 @@ module CanTango
|
|
8
8
|
# builds a list of Permits for each role group of the current ability user (or account)
|
9
9
|
# @return [Array<RoleGroupPermit::Base>] the role group permits built for this ability
|
10
10
|
def build
|
11
|
-
|
12
|
-
puts "Not building any RoleGroupPermit" if CanTango.debug?
|
13
|
-
return [] if role_groups.empty?
|
14
|
-
end
|
15
|
-
|
16
|
-
role_groups.inject([]) do |permits, role_group|
|
11
|
+
matching_permits = matching_role_groups(roles).inject([]) do |permits, role_group|
|
17
12
|
puts "Building RoleGroupPermit for #{role_group}" if CanTango.debug?
|
18
13
|
(permits << create_permit(role_group)) if valid?(role_group)
|
19
14
|
permits
|
20
15
|
end.compact
|
21
|
-
|
16
|
+
|
17
|
+
if matching_permits.empty?
|
18
|
+
puts "Not building any RoleGroupPermits since no role groups are roles that are members of a role group could be found for the permission candidate" if CanTango.debug?
|
19
|
+
return []
|
20
|
+
end
|
21
|
+
end
|
22
22
|
|
23
23
|
def valid? role_group
|
24
24
|
return true if !role_groups_filter?
|
@@ -31,6 +31,22 @@ module CanTango
|
|
31
31
|
|
32
32
|
private
|
33
33
|
|
34
|
+
def matching_role_groups roles
|
35
|
+
role_groups | matching_role_groups_for(roles)
|
36
|
+
end
|
37
|
+
|
38
|
+
# will also run role_groups for which any role of the candidate is a member
|
39
|
+
# so if the candidate is a user and the user has a :trustee role and this role is part of the :trust role group,
|
40
|
+
# then the :trust role group permit will be run!
|
41
|
+
# Thus if the candidate has a particular role group or just has a role belonging to that role group, the permit
|
42
|
+
# for that role group will be run
|
43
|
+
def matching_role_groups_for roles
|
44
|
+
roles.inject([]) do |groups, role|
|
45
|
+
groups << subject.role_groups_for(role) if subject.respond_to?(:role_groups_for)
|
46
|
+
groups
|
47
|
+
end.flatten.compact.uniq
|
48
|
+
end
|
49
|
+
|
34
50
|
def role_groups_filter?
|
35
51
|
CanTango.config.role_groups.filter?
|
36
52
|
end
|
@@ -28,7 +28,6 @@ module CanTango
|
|
28
28
|
super
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
31
|
# In a specific Role based Permit you can use
|
33
32
|
# def permit? user, options = {}
|
34
33
|
# ... permission logic follows
|
@@ -49,7 +48,7 @@ module CanTango
|
|
49
48
|
def valid_for? subject
|
50
49
|
in_role? subject
|
51
50
|
end
|
52
|
-
|
51
|
+
|
53
52
|
protected
|
54
53
|
|
55
54
|
include CanTango::Helpers::RoleMethods
|
@@ -8,9 +8,10 @@ module CanTango::Rails::Helpers::RestHelper
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def link_to_new obj, user_type, options = {}
|
11
|
-
|
11
|
+
clazz = obj.kind_of?(Class) ? obj : obj.class
|
12
|
+
return unless can_perform_action?(user_type, :create, clazz)
|
12
13
|
# use i18n translation on label
|
13
|
-
link_to t(".create"), send(action_method
|
14
|
+
link_to t(".create"), send(action_method clazz, :new, options)
|
14
15
|
end
|
15
16
|
|
16
17
|
def link_to_delete obj, user_type, options = {}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module CanTango
|
2
|
+
class UserAcEngine < Engine
|
3
|
+
autoload_modules :Executor
|
4
|
+
|
5
|
+
def initialize ability
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def execute!
|
10
|
+
return if !valid?
|
11
|
+
debug "User AC Engine executing..."
|
12
|
+
|
13
|
+
permissions.each do |permission|
|
14
|
+
ability.can permission.action.to_sym, permission.thing_type.constantize do |thing|
|
15
|
+
thing.nil? || permission.thing_id.nil? || permission.thing_id == thing.id
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def valid?
|
21
|
+
return false if !valid_mode?
|
22
|
+
permissions.empty? ? invalid : true
|
23
|
+
end
|
24
|
+
|
25
|
+
def engine_name
|
26
|
+
:user_ac
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def permissions
|
32
|
+
candidate.respond_to?(:permissions) ? candidate.permissions : []
|
33
|
+
end
|
34
|
+
|
35
|
+
def invalid
|
36
|
+
debug "No permissions for #{candidate} found!"
|
37
|
+
false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# This class is responsible for executing a set of similar Permits and collecting their rule results into one rule collection
|
2
|
+
# which can be cached under some key and later reused
|
3
|
+
#
|
4
|
+
module CanTango
|
5
|
+
class UserAcEngine < Engine
|
6
|
+
class Executor
|
7
|
+
include CanTango::Ability::CacheHelpers
|
8
|
+
|
9
|
+
attr_reader :ability, :permits
|
10
|
+
|
11
|
+
delegate :session, :user, :subject, :cached?, :to => :ability
|
12
|
+
|
13
|
+
def initialize ability, permit_type, permissions
|
14
|
+
@ability = ability
|
15
|
+
@permissions = permissions
|
16
|
+
end
|
17
|
+
|
18
|
+
def cache_key
|
19
|
+
:user_ac
|
20
|
+
end
|
21
|
+
|
22
|
+
def rules
|
23
|
+
@rules ||= []
|
24
|
+
end
|
25
|
+
|
26
|
+
def clear_rules!
|
27
|
+
@rules ||= []
|
28
|
+
end
|
29
|
+
|
30
|
+
def cache
|
31
|
+
@cache ||= CanTango::Ability::Cache.new self, :cache_key => cache_key, :key_method_names => key_method_names
|
32
|
+
end
|
33
|
+
|
34
|
+
def execute!
|
35
|
+
return if cached_rules?
|
36
|
+
|
37
|
+
clear_rules!
|
38
|
+
permit_rules
|
39
|
+
|
40
|
+
cache_rules!
|
41
|
+
end
|
42
|
+
|
43
|
+
def permit_rules
|
44
|
+
# TODO: somehow type specific caching of result of permits!
|
45
|
+
permits.each do |permit|
|
46
|
+
CanTango.config.permits.was_executed(permit, ability) if CanTango.debug?
|
47
|
+
break if permit.execute == :break
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def key_method_names
|
54
|
+
[:permissions_hash]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
@@ -3,11 +3,14 @@ class Module
|
|
3
3
|
self.send :include, CanTango::Users::User
|
4
4
|
self.send :include, CanTango::Users::Masquerade if options[:masquerade]
|
5
5
|
end
|
6
|
+
alias_method :cantango_user, :tango_user
|
6
7
|
|
7
8
|
def tango_user_account options = {}
|
8
9
|
self.send :include, CanTango::Users::UserAccount
|
9
10
|
self.send :include, CanTango::Users::Masquerade if options[:masquerade]
|
10
11
|
end
|
12
|
+
alias_method :tango_account, :tango_user_account
|
13
|
+
alias_method :cantango_account, :tango_user_account
|
11
14
|
|
12
15
|
def masquerader
|
13
16
|
self.send :include, CanTango::Users::Masquerade
|
data/lib/cantango/users/user.rb
CHANGED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'generators/cantango/base'
|
2
|
+
|
3
|
+
module Cantango
|
4
|
+
module Generators
|
5
|
+
class PermissionGenerator < Cantango::Generators::Base
|
6
|
+
desc "Creates a Permission for a model in 'app/models'"
|
7
|
+
|
8
|
+
argument :name, :type => :string,
|
9
|
+
:desc => "Model to create Permission model for"
|
10
|
+
|
11
|
+
source_root File.dirname(__FILE__) + '/templates'
|
12
|
+
|
13
|
+
def main_flow
|
14
|
+
relational
|
15
|
+
end
|
16
|
+
|
17
|
+
def relational
|
18
|
+
Rails::Generators.invoke "model", ['Permission', "#{name}_id:integer", "thing_id:integer", "thing_type:string", "action:string"
|
19
|
+
|
20
|
+
puts "Manual Modifications to Permission model:"
|
21
|
+
puts "-----------------------------------------"
|
22
|
+
puts "belongs_to :#{name}"
|
23
|
+
puts "belongs_to :thing, :polymorphic => true"
|
24
|
+
|
25
|
+
puts "Manual Modifications to #{name.to_s.camelize} model:"
|
26
|
+
puts "has_many :permissions"
|
27
|
+
puts "-----------------------------------------"
|
28
|
+
|
29
|
+
puts "and then run:"
|
30
|
+
puts "rake db:migrate"
|
31
|
+
end
|
32
|
+
|
33
|
+
def document_store
|
34
|
+
Rails::Generators.invoke "model", ['Permission']
|
35
|
+
# use rails_artifactor to edit model?!
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|