bali 2.4.0 → 6.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +5 -13
  2. data/.gitignore +2 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +44 -2
  5. data/gemfiles/Gemfile-rails.5.0.x +7 -0
  6. data/gemfiles/Gemfile-rails.5.1.x +6 -0
  7. data/gemfiles/Gemfile-rails.5.2.x +6 -0
  8. data/gemfiles/Gemfile-rails.6.0.x +5 -0
  9. data/gemfiles/Gemfile-rails.edge +14 -0
  10. data/lib/bali.rb +33 -22
  11. data/lib/bali/config.rb +12 -0
  12. data/lib/bali/dsl_error.rb +3 -0
  13. data/lib/bali/{foundations/exceptions/bali_error.rb → error.rb} +0 -0
  14. data/lib/bali/judge.rb +221 -0
  15. data/lib/bali/printer.rb +42 -31
  16. data/lib/bali/rails/action_controller.rb +17 -0
  17. data/lib/bali/rails/action_view.rb +12 -0
  18. data/lib/bali/rails/active_record.rb +11 -0
  19. data/lib/bali/railtie.rb +13 -0
  20. data/lib/bali/role.rb +110 -0
  21. data/lib/bali/rspec/able_to_matcher.rb +39 -0
  22. data/lib/bali/rule.rb +17 -0
  23. data/lib/bali/ruler.rb +38 -0
  24. data/lib/bali/rules.rb +51 -0
  25. data/lib/bali/statics/active_record.rb +2 -0
  26. data/lib/bali/statics/authorizer.rb +65 -0
  27. data/lib/bali/statics/record.rb +13 -0
  28. data/lib/bali/statics/scope_ruler.rb +39 -0
  29. data/lib/bali/tasks/bali/print_rules.rake +9 -0
  30. data/lib/bali/version.rb +1 -1
  31. data/lib/generators/rails/USAGE +8 -0
  32. data/lib/generators/rails/rules_generator.rb +17 -0
  33. data/lib/generators/rails/templates/rules.rb +4 -0
  34. data/lib/generators/rspec/rules_generator.rb +12 -0
  35. data/lib/generators/rspec/templates/rules_spec.rb +7 -0
  36. metadata +131 -49
  37. data/lib/bali/dsl/map_rules_dsl.rb +0 -75
  38. data/lib/bali/dsl/rules_for_dsl.rb +0 -130
  39. data/lib/bali/foundations/all_foundations.rb +0 -17
  40. data/lib/bali/foundations/exceptions/authorization_error.rb +0 -38
  41. data/lib/bali/foundations/exceptions/dsl_error.rb +0 -3
  42. data/lib/bali/foundations/exceptions/objection_error.rb +0 -3
  43. data/lib/bali/foundations/judger/judge.rb +0 -329
  44. data/lib/bali/foundations/judger/negative_judge.rb +0 -40
  45. data/lib/bali/foundations/judger/positive_judge.rb +0 -41
  46. data/lib/bali/foundations/role_extractor.rb +0 -61
  47. data/lib/bali/foundations/rule/rule.rb +0 -55
  48. data/lib/bali/foundations/rule/rule_class.rb +0 -54
  49. data/lib/bali/foundations/rule/rule_group.rb +0 -91
  50. data/lib/bali/integrators/all_integrators.rb +0 -8
  51. data/lib/bali/integrators/rule_class_integrator.rb +0 -27
  52. data/lib/bali/integrators/rule_group_integrator.rb +0 -29
  53. data/lib/bali/integrators/rule_integrator.rb +0 -56
  54. data/lib/bali/objector.rb +0 -173
@@ -1,61 +0,0 @@
1
- class Bali::RoleExtractor
2
- attr_reader :arg
3
-
4
- # argument can be anything, as long as role extractor know how to extract
5
- def initialize(arg)
6
- @arg = arg
7
- end
8
-
9
- def get_roles(object = @arg)
10
- case object
11
- when String; get_role_string(object)
12
- when Symbol; get_role_symbol(object)
13
- when NilClass; get_role_nil(object)
14
- when Array; get_role_array(object)
15
- else
16
- get_role_object(object)
17
- end
18
- end
19
-
20
- private
21
- def get_role_string(object)
22
- [object]
23
- end
24
-
25
- def get_role_symbol(object)
26
- [object]
27
- end
28
-
29
- def get_role_nil(object)
30
- [object]
31
- end
32
-
33
- def get_role_array(object)
34
- object
35
- end
36
-
37
- # this case, _subtarget_roles is an object but not a symbol or a string
38
- # let's try to deduct subtarget's roles
39
- def get_role_object(object)
40
- object_class = object.class.to_s
41
-
42
- # variable to hold deducted role of the passed object
43
- deducted_roles = nil
44
- role_extracted = false
45
-
46
- Bali::TRANSLATED_SUBTARGET_ROLES.each do |current_subtarget_class, roles_field_name|
47
- if object_class == current_subtarget_class
48
- deducted_roles = object.send(roles_field_name)
49
- deducted_roles = get_roles(deducted_roles)
50
- role_extracted = true
51
- break
52
- end # if matching class
53
- end # each TRANSLATED_SUBTARGET_ROLES
54
-
55
- unless role_extracted
56
- raise Bali::AuthorizationError, "Bali does not know how to process roles: #{object}"
57
- end
58
-
59
- deducted_roles
60
- end
61
- end
@@ -1,55 +0,0 @@
1
- # for internal use, representing one, single, atomic rule
2
- class Bali::Rule
3
- # auth_val is either :can or :cannot
4
- attr_reader :auth_val
5
-
6
- # what is the operation: create, update, delete, or any other
7
- attr_reader :operation
8
-
9
- # if decider is defined, a rule is executed only if decider evaluates to true
10
- attr_accessor :decider
11
- # either unless or if
12
- attr_reader :decider_type
13
-
14
- def initialize(auth_val, operation)
15
- self.auth_val = auth_val
16
- @operation = operation
17
- self
18
- end
19
-
20
- def clone
21
- cloned_rule = Bali::Rule.new(auth_val, operation)
22
- cloned_rule.decider = decider if decider
23
- cloned_rule.decider_type = decider_type if decider_type
24
-
25
- cloned_rule
26
- end
27
-
28
- def auth_val=(aval)
29
- # TODO: in version 3 remove :cant
30
- if aval == :can || aval == :cannot
31
- @auth_val = aval
32
- elsif aval == :cant
33
- @auth_val = :cannot
34
- else
35
- fail Bali::DslError, "auth_val can only either be :can or :cannot"
36
- end
37
- end
38
-
39
- def decider_type=(dectype)
40
- if dectype == :if || dectype == :unless
41
- @decider_type = dectype
42
- else
43
- fail Bali::DslError, "decider type not allowed"
44
- end
45
- end
46
-
47
- def is_discouragement?
48
- # TODO: in version 3.0 remove :cant
49
- self.auth_val == :cannot || self.auth_val == :cant
50
- end
51
-
52
- def has_decider?
53
- self.decider.is_a?(Proc) && !self.decider_type.nil?
54
- end
55
- end
@@ -1,54 +0,0 @@
1
- # the parent of all Bali::RuleGroup.
2
- class Bali::RuleClass
3
- attr_reader :target_class
4
-
5
- # consist of canonised subtarget and its rule group, eg:
6
- # {
7
- # general_user: RuleGroup
8
- # }
9
- attr_accessor :rule_groups
10
-
11
- # rule group for "other" subtargets, always checked the last time
12
- # after the "more proper" rule groups are checked
13
- attr_accessor :others_rule_group
14
-
15
- def initialize(target_class)
16
- @target_class = target_class
17
- self.rule_groups = {}
18
- self.others_rule_group = Bali::RuleGroup.new(target_class, "__*__")
19
- end
20
-
21
- def add_rule_group(rule_group)
22
- target_user = rule_group.subtarget
23
- if target_user == "__*__" || target_user == :"__*__"
24
- self.others_rule_group = rule_group
25
- else
26
- self.rule_groups[rule_group.subtarget] = rule_group
27
- end
28
- end
29
-
30
- def rules_for(subtarget)
31
- return others_rule_group if subtarget == "__*__"
32
- subtarget = Bali::RuleGroup.canon_name(subtarget)
33
- self.rule_groups[subtarget]
34
- end
35
-
36
- # options can contains:
37
- # :target_class => identifying the target class on which the clone will be applied
38
- def clone(options = {})
39
- target_class = options.fetch(:target_class)
40
- cloned_rc = Bali::RuleClass.new(target_class)
41
-
42
- rule_groups.each do |subtarget, rule_group|
43
- rule_group_clone = rule_group.clone
44
- rule_group_clone.target = target_class
45
- cloned_rc.add_rule_group(rule_group_clone)
46
- end
47
-
48
- others_rule_group_clone = others_rule_group.clone
49
- others_rule_group_clone.target = target_class
50
- cloned_rc.others_rule_group = others_rule_group_clone
51
-
52
- cloned_rc
53
- end
54
- end
@@ -1,91 +0,0 @@
1
- class Bali::RuleGroup
2
- # the target class
3
- attr_accessor :target
4
-
5
- # the user to which this rule group is applied
6
- attr_accessor :subtarget
7
-
8
- # what can be done and what cannot be done
9
- attr_accessor :cans, :cants
10
-
11
- # if set to true then the subtarget can do anything
12
- attr_accessor :zeus
13
- alias :zeus? :zeus
14
-
15
- # if set to true, well, cannot do anything
16
- attr_accessor :plant
17
- alias :plant? :plant
18
-
19
- # allowing "general user" and :general_user to route to the same rule group
20
- def self.canon_name(subtarget)
21
- if subtarget.is_a?(String)
22
- return subtarget.gsub(" ", "_").to_sym
23
- else
24
- return subtarget
25
- end
26
- end
27
-
28
- def initialize(target, subtarget)
29
- self.target = target
30
- self.subtarget = Bali::RuleGroup.canon_name(subtarget)
31
-
32
- self.cans = {}
33
- self.cants = {}
34
-
35
- # by default, rule group is neither zeus nor plant
36
- # it is neutral.
37
- # meaning, it is neither allowed to do everything, nor it is
38
- # prohibited to do anything. neutral.
39
- self.zeus = false
40
- self.plant = false
41
- end
42
-
43
- def clone
44
- cloned_rg = Bali::RuleGroup.new(target, subtarget)
45
- cans.each_value { |can_rule| cloned_rg.add_rule(can_rule.clone) }
46
- cants.each_value { |cant_rule| cloned_rg.add_rule(cant_rule.clone) }
47
- cloned_rg.zeus = zeus
48
- cloned_rg.plant = plant
49
-
50
- cloned_rg
51
- end
52
-
53
- def add_rule(rule)
54
- # operation cannot be defined twice
55
- operation = rule.operation.to_sym
56
-
57
- return if self.cants[operation] && self.cans[operation]
58
-
59
- if rule.is_discouragement?
60
- self.cants[operation] = rule
61
- self.cans.delete operation
62
- else
63
- self.cans[operation] = rule
64
- self.cants.delete operation
65
- end
66
- end
67
-
68
- def clear_rules
69
- self.cans = {}
70
- self.cants = {}
71
- end
72
-
73
- def get_rule(auth_val, operation)
74
- rule = nil
75
- case auth_val
76
- when :can, "can"
77
- rule = self.cans[operation.to_sym]
78
- when :cannot, "cannot"
79
- rule = self.cants[operation.to_sym]
80
- else
81
- fail Bali::DslError, "Undefined operation: #{auth_val}"
82
- end
83
-
84
- rule
85
- end
86
-
87
- # all rules
88
- def rules
89
- self.cans.values + self.cants.values
90
- end
91
- end
@@ -1,8 +0,0 @@
1
- module Bali
2
- module Integrator
3
- end
4
- end
5
-
6
- require_relative "rule_class_integrator"
7
- require_relative "rule_group_integrator"
8
- require_relative "rule_integrator"
@@ -1,27 +0,0 @@
1
- module Bali
2
- module Integrator
3
- # high-level functions to access and manage RuleClass classes
4
- module RuleClass
5
-
6
- module_function
7
-
8
- # return all rule classes
9
- def all
10
- Bali::RULE_CLASS_MAP
11
- end
12
-
13
- # return all rule class of a target
14
- def for(target)
15
- Bali::RULE_CLASS_MAP[target.to_s]
16
- end
17
-
18
- # add a new rule class
19
- def add(rule_class)
20
- target = rule_class.target_class
21
-
22
- Bali::RULE_CLASS_MAP[target.to_s] = rule_class
23
- rule_class
24
- end # add_rule_class
25
- end
26
- end
27
- end
@@ -1,29 +0,0 @@
1
- module Bali
2
- module Integrator
3
- module RuleGroup
4
-
5
- module_function
6
-
7
- # attempt to search the rule group,
8
- # but if not exist, will return nil
9
- def for(target_class, subtarget)
10
- rule_class = Bali::Integrator::RuleClass.for(target_class)
11
- rule_class.nil? ? nil : rule_class.rules_for(subtarget)
12
- end
13
-
14
- # make a rule group a zeus, that is, he can do everything, unless
15
- # specified more specifically otherwise by a definite rule
16
- def make_zeus(rule_group)
17
- rule_group.zeus = true
18
- rule_group.plant = false
19
- end
20
-
21
- # make a rule group a plant, that is, he cannot do everything, unless
22
- # specified more specifically otherwise by a definite rule
23
- def make_plant(rule_group)
24
- rule_group.plant = true
25
- rule_group.zeus = false
26
- end
27
- end
28
- end
29
- end
@@ -1,56 +0,0 @@
1
- module Bali
2
- module Integrator
3
- module Rule
4
-
5
- module_function
6
-
7
- # process conditional statement in rule definition
8
- # conditional hash: {if: proc} or {unless: proc}
9
- def embed_condition(rule, conditional_hash = nil)
10
- return if conditional_hash.nil?
11
-
12
- condition_type = conditional_hash.keys[0].to_s.downcase
13
- condition_type_symb = condition_type.to_sym
14
-
15
- if condition_type_symb == :if || condition_type_symb == :unless
16
- rule.decider = conditional_hash.values[0]
17
- rule.decider_type = condition_type_symb
18
- end
19
- nil
20
- end
21
-
22
- # to define can and cant is basically using this method
23
- # args can comprises of symbols, and hash (for condition)
24
- def add(auth_val, rule_group, *args)
25
- conditional_hash = nil
26
- operations = []
27
-
28
- # scan args for options
29
- args.each do |elm|
30
- if elm.is_a?(Hash)
31
- conditional_hash = elm
32
- else
33
- operations << elm
34
- end
35
- end
36
-
37
- # add operation one by one
38
- operations.each do |op|
39
- rule = Bali::Rule.new(auth_val, op)
40
- Bali::Integrator::Rule.embed_condition(rule, conditional_hash)
41
- rule_group.add_rule(rule)
42
- end
43
- end # bali_process_auth_rules
44
-
45
- # add can rule programatically
46
- def add_can(rule_group, *args)
47
- add :can, rule_group, *args
48
- end
49
-
50
- # add cannot rule programatically
51
- def add_cannot(rule_group, *args)
52
- add :cannot, rule_group, *args
53
- end
54
- end
55
- end
56
- end
@@ -1,173 +0,0 @@
1
- # module that will be included in each instantiated target classes as defined
2
- # in map_rules
3
- module Bali::Objector
4
- def self.included(base)
5
- base.extend Bali::Objector::Statics
6
- end
7
-
8
- # check whether user can/cant perform an operation, return true when positive
9
- # or false otherwise
10
- def can?(subtargets, operation)
11
- self.class.can?(subtargets, operation, self)
12
- end
13
-
14
- # check whether user can/cant perform an operation, raise an error when access
15
- # is denied
16
- def can!(subtargets, operation)
17
- self.class.can!(subtargets, operation, self)
18
- end
19
-
20
- # check whether user can/cant perform an operation, return true when negative
21
- # or false otherwise
22
- def cannot?(subtargets, operation)
23
- self.class.cannot?(subtargets, operation, self)
24
- end
25
-
26
- # check whether user can/cant perform an operation, raise an error when access
27
- # is given
28
- def cannot!(subtargets, operation)
29
- self.class.cannot!(subtargets, operation, self)
30
- end
31
-
32
- def cant?(subtargets, operation)
33
- puts "Deprecation Warning: please use cannot? instead, cant? will be deprecated on major release 3.0"
34
- cannot?(subtargets, operation)
35
- end
36
-
37
- def cant!(subtargets, operation)
38
- puts "Deprecation Warning: please use cannot! instead, cant! will be deprecated on major release 3.0"
39
- cannot!(subtargets, operation)
40
- end
41
- end
42
-
43
- # to allow class-level objection
44
- module Bali::Objector::Statics
45
- # get the proper roles for the subtarget, for any type of subtarget
46
- def bali_translate_subtarget_roles(arg)
47
- role_extractor = Bali::RoleExtractor.new(arg)
48
- role_extractor.get_roles
49
- end
50
-
51
- def can?(subtarget_roles, operation, record = self, options = {})
52
- subs = bali_translate_subtarget_roles(subtarget_roles)
53
- # well, it is largely not used unless decider's is 2 arity
54
- original_subtarget = options[:original_subtarget].nil? ? subtarget_roles : options[:original_subtarget]
55
-
56
- judgement_value = false
57
- role = nil
58
- judger = nil
59
-
60
- subs.each do |subtarget|
61
- next if judgement_value == true
62
-
63
- judge = Bali::Judger::Judge.build(:can, {
64
- subtarget: subtarget,
65
- original_subtarget: original_subtarget,
66
- operation: operation,
67
- record: record
68
- })
69
- judgement_value = judge.judgement
70
-
71
- role = subtarget
72
- end
73
-
74
- if block_given?
75
- yield original_subtarget, role, judgement_value
76
- end
77
-
78
- judgement_value
79
- rescue => e
80
- if e.is_a?(Bali::AuthorizationError) || e.is_a?(Bali::Error)
81
- raise e
82
- else
83
- raise Bali::ObjectionError, e.message, e.backtrace
84
- end
85
- end
86
-
87
- def cannot?(subtarget_roles, operation, record = self, options = {})
88
- subs = bali_translate_subtarget_roles subtarget_roles
89
- original_subtarget = options[:original_subtarget].nil? ? subtarget_roles : options[:original_subtarget]
90
-
91
- judgement_value = true
92
- role = nil
93
- judger = nil
94
-
95
- subs.each do |subtarget|
96
- next if judgement_value == false
97
-
98
- judge = Bali::Judger::Judge.build(:cannot, {
99
- subtarget: subtarget,
100
- original_subtarget: original_subtarget,
101
- operation: operation,
102
- record: record
103
- })
104
- judgement_value = judge.judgement
105
-
106
- role = subtarget
107
- end
108
-
109
- if block_given?
110
- yield original_subtarget, role, judgement_value
111
- end
112
-
113
- judgement_value
114
- rescue => e
115
- if e.is_a?(Bali::AuthorizationError)
116
- raise e
117
- else
118
- raise Bali::ObjectionError, e.message, e.backtrace
119
- end
120
- end
121
-
122
- def can!(subtarget_roles, operation, record = self, options = {})
123
- can?(subtarget_roles, operation, record, options) do |original_subtarget, role, can_value|
124
- if !can_value
125
- auth_error = Bali::AuthorizationError.new
126
- auth_error.auth_level = :can
127
- auth_error.operation = operation
128
- auth_error.role = role
129
- auth_error.target = record
130
- auth_error.subtarget = original_subtarget
131
-
132
- if role
133
- auth_error.subtarget = original_subtarget if !(original_subtarget.is_a?(Symbol) || original_subtarget.is_a?(String) || original_subtarget.is_a?(Array))
134
- end
135
-
136
- raise auth_error
137
- else
138
- return can_value
139
- end # if cannot is false, means cannot
140
- end # can?
141
- end
142
-
143
- def cant!(subtarget_roles, operation, record = self, options = {})
144
- puts "Deprecation Warning: please use cannot! instead, cant! will be deprecated on major release 3.0"
145
- cannot!(subtarget_roles, operation, record, options)
146
- end
147
-
148
- def cant?(subtarget_roles, operation)
149
- puts "Deprecation Warning: please use cannot? instead, cant? will be deprecated on major release 3.0"
150
- cannot?(subtarget_roles, operation)
151
- end
152
-
153
- def cannot!(subtarget_roles, operation, record = self, options = {})
154
- cannot?(subtarget_roles, operation, record, options) do |original_subtarget, role, cant_value|
155
- if cant_value == false
156
- auth_error = Bali::AuthorizationError.new
157
- auth_error.auth_level = :cannot
158
- auth_error.operation = operation
159
- auth_error.role = role
160
- auth_error.target = record
161
- auth_error.subtarget = original_subtarget
162
-
163
- if role
164
- auth_error.subtarget = original_subtarget if !(original_subtarget.is_a?(Symbol) || original_subtarget.is_a?(String) || original_subtarget.is_a?(Array))
165
- end
166
-
167
- raise auth_error
168
- else
169
- return cant_value
170
- end # if cannot is false, means can
171
- end # cannot?
172
- end
173
- end