bali 2.4.0 → 6.0.1

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