forest_liana 7.8.0 → 8.0.0.beta.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/forest_liana/actions_controller.rb +5 -3
  3. data/app/controllers/forest_liana/application_controller.rb +15 -0
  4. data/app/controllers/forest_liana/resources_controller.rb +31 -57
  5. data/app/controllers/forest_liana/smart_actions_controller.rb +44 -58
  6. data/app/controllers/forest_liana/stats_controller.rb +14 -58
  7. data/app/services/forest_liana/ability/exceptions/access_denied.rb +16 -0
  8. data/app/services/forest_liana/ability/exceptions/action_condition_error.rb +16 -0
  9. data/app/services/forest_liana/ability/exceptions/require_approval.rb +18 -0
  10. data/app/services/forest_liana/ability/exceptions/trigger_forbidden.rb +16 -0
  11. data/app/services/forest_liana/ability/fetch.rb +23 -0
  12. data/app/services/forest_liana/ability/permission/request_permission.rb +19 -0
  13. data/app/services/forest_liana/ability/permission/smart_action_checker.rb +71 -0
  14. data/app/services/forest_liana/ability/permission.rb +148 -0
  15. data/app/services/forest_liana/ability.rb +24 -0
  16. data/app/services/forest_liana/filters_parser.rb +7 -7
  17. data/app/services/forest_liana/leaderboard_stat_getter.rb +7 -7
  18. data/app/services/forest_liana/line_stat_getter.rb +8 -8
  19. data/app/services/forest_liana/pie_stat_getter.rb +17 -17
  20. data/app/services/forest_liana/stat_getter.rb +1 -2
  21. data/app/services/forest_liana/value_stat_getter.rb +7 -7
  22. data/lib/forest_liana/bootstrapper.rb +1 -1
  23. data/lib/forest_liana/version.rb +1 -1
  24. data/spec/dummy/lib/forest_liana/collections/island.rb +1 -1
  25. data/spec/requests/actions_controller_spec.rb +3 -4
  26. data/spec/requests/count_spec.rb +5 -9
  27. data/spec/requests/resources_spec.rb +55 -11
  28. data/spec/requests/stats_spec.rb +103 -42
  29. data/spec/services/forest_liana/ability/ability_spec.rb +48 -0
  30. data/spec/services/forest_liana/ability/permission/smart_action_checker_spec.rb +357 -0
  31. data/spec/services/forest_liana/ability/permission_spec.rb +332 -0
  32. data/spec/services/forest_liana/filters_parser_spec.rb +0 -12
  33. data/spec/services/forest_liana/line_stat_getter_spec.rb +9 -9
  34. data/spec/services/forest_liana/pie_stat_getter_spec.rb +7 -7
  35. data/spec/services/forest_liana/value_stat_getter_spec.rb +11 -11
  36. data/spec/spec_helper.rb +1 -0
  37. metadata +33 -17
  38. data/app/services/forest_liana/permissions_checker.rb +0 -223
  39. data/app/services/forest_liana/permissions_formatter.rb +0 -52
  40. data/app/services/forest_liana/permissions_getter.rb +0 -59
  41. data/spec/services/forest_liana/permissions_checker_acl_disabled_spec.rb +0 -713
  42. data/spec/services/forest_liana/permissions_checker_acl_enabled_spec.rb +0 -845
  43. data/spec/services/forest_liana/permissions_checker_live_queries_spec.rb +0 -175
  44. data/spec/services/forest_liana/permissions_formatter_spec.rb +0 -222
  45. data/spec/services/forest_liana/permissions_getter_spec.rb +0 -83
@@ -4,12 +4,12 @@ require 'json'
4
4
  describe "Stats", type: :request do
5
5
 
6
6
  token = JWT.encode({
7
- id: 38,
7
+ id: 1,
8
8
  email: 'michael.kelso@that70.show',
9
9
  first_name: 'Michael',
10
10
  last_name: 'Kelso',
11
11
  team: 'Operations',
12
- rendering_id: 16,
12
+ rendering_id: '1',
13
13
  exp: Time.now.to_i + 2.weeks.to_i,
14
14
  permission_level: 'admin'
15
15
  }, ForestLiana.auth_secret, 'HS256')
@@ -23,7 +23,7 @@ describe "Stats", type: :request do
23
23
  let(:schema) {
24
24
  [
25
25
  ForestLiana::Model::Collection.new({
26
- name: 'Products',
26
+ name: 'Product',
27
27
  fields: [],
28
28
  actions: []
29
29
  })
@@ -31,62 +31,113 @@ describe "Stats", type: :request do
31
31
  }
32
32
 
33
33
  before do
34
- allow(ForestLiana).to receive(:apimap).and_return(schema)
35
- end
34
+ Rails.cache.write('forest.users', {'1' => { 'id' => 1, 'roleId' => 1, 'rendering_id' => '1' }})
35
+ Rails.cache.write('forest.has_permission', true)
36
+ allow_any_instance_of(ForestLiana::Ability::Fetch)
37
+ .to receive(:get_permissions)
38
+ .and_return(
39
+ {
40
+ "stats" => [
41
+ {
42
+ "type" => "Value",
43
+ "filter" => nil,
44
+ "aggregator" => "Count",
45
+ "aggregateFieldName" => nil,
46
+ "sourceCollectionName" => "Owner"
47
+ },
48
+ {
49
+ "type" => "Value",
50
+ "query" => "SELECT COUNT(*) AS value FROM products;"
51
+ }
52
+ ],
53
+ }
54
+ )
55
+
56
+ ForestLiana::ScopeManager.class_variable_set(:@@scopes_cache, {
57
+ '1' => {
58
+ :fetched_at => Time.now,
59
+ :scopes => {}
60
+ }
61
+ })
36
62
 
37
- before(:each) do
63
+ allow(ForestLiana).to receive(:apimap).and_return(schema)
38
64
  allow(ForestLiana::IpWhitelist).to receive(:retrieve) { true }
39
65
  allow(ForestLiana::IpWhitelist).to receive(:is_ip_whitelist_retrieved) { true }
40
66
  allow(ForestLiana::IpWhitelist).to receive(:is_ip_valid) { true }
41
-
42
- allow_any_instance_of(ForestLiana::PermissionsChecker).to receive(:is_authorized?) { true }
43
-
44
- allow_any_instance_of(ForestLiana::ValueStatGetter).to receive(:perform) { true }
45
- allow_any_instance_of(ForestLiana::QueryStatGetter).to receive(:perform) { true }
46
67
  end
47
68
 
48
-
49
-
50
69
  describe 'POST /stats/:collection' do
51
- params = { type: 'Value', collection: 'User', aggregate: 'Count' }
52
-
70
+ params = { type: 'Value', collection: 'Owner', aggregator: 'Count', sourceCollectionName: 'Owner', aggregateFieldName: nil, filter: nil}
53
71
  it 'should respond 200' do
54
- data = ForestLiana::Model::Stat.new(value: { countCurrent: 0, countPrevious: 0 })
55
- allow_any_instance_of(ForestLiana::ValueStatGetter).to receive(:record) { data }
56
- # NOTICE: bypass : find_resource error
57
- allow_any_instance_of(ForestLiana::StatsController).to receive(:find_resource) { true }
58
- allow(ForestLiana::QueryHelper).to receive(:get_one_association_names_symbol) { true }
72
+ Rails.cache.delete('forest.stats')
73
+ post '/forest/stats/Owner', params: JSON.dump(params), headers: headers
59
74
 
60
- post '/forest/stats/Products', params: JSON.dump(params), headers: headers
61
75
  expect(response.status).to eq(200)
62
76
  end
63
77
 
64
- it 'should respond 401 with no headers' do
65
- post '/forest/stats/Products', params: JSON.dump(params)
66
- expect(response.status).to eq(401)
78
+ it 'should respond 200 with Objective chart' do
79
+ Rails.cache.delete('forest.stats')
80
+ params = {type: "Objective", sourceCollectionName: "Owner", aggregateFieldName: nil, aggregator: "Count", objective: 200, filter: nil, contextVariables: {}}
81
+ post '/forest/stats/Owner', params: JSON.dump(params), headers: headers
82
+
83
+ expect(response.status).to eq(200)
67
84
  end
68
85
 
69
- it 'should respond 404 with non existing collection' do
70
- allow_any_instance_of(ForestLiana::ValueStatGetter).to receive(:record) { nil }
86
+ it 'should respond 200 with Pie chart' do
87
+ Rails.cache.delete('forest.stats')
88
+ params = { type: "Pie", sourceCollectionName: "Owner", aggregateFieldName: nil, groupByFieldName: "id", aggregator: "Count", filter: nil, contextVariables:nil }
89
+ post '/forest/stats/Owner', params: JSON.dump(params), headers: headers
71
90
 
72
- post '/forest/stats/NoCollection', params: {}, headers: headers
73
- expect(response.status).to eq(404)
91
+ expect(response.status).to eq(200)
92
+ end
93
+
94
+ it 'should respond 200 with Line chart' do
95
+ Rails.cache.delete('forest.stats')
96
+ params = { type: "Line", sourceCollectionName: "Owner", aggregateFieldName: nil, groupByFieldName: "hired_at", aggregator: "Count", timeRange: "Week", filter: nil, contextVariables:nil }
97
+ post '/forest/stats/Owner', params: JSON.dump(params), headers: headers
98
+
99
+ expect(response.status).to eq(200)
74
100
  end
75
101
 
76
102
  it 'should respond 403 Forbidden' do
77
- allow_any_instance_of(ForestLiana::PermissionsChecker).to receive(:is_authorized?) { false }
103
+ no_admin_token = JWT.encode({
104
+ id: 1,
105
+ email: 'michael.kelso@that70.show',
106
+ first_name: 'Michael',
107
+ last_name: 'Kelso',
108
+ team: 'Operations',
109
+ rendering_id: '1',
110
+ exp: Time.now.to_i + 2.weeks.to_i,
111
+ permission_level: 'user'
112
+ }, ForestLiana.auth_secret, 'HS256')
113
+
114
+ no_admin_headers = {
115
+ 'Accept' => 'application/json',
116
+ 'Content-Type' => 'application/json',
117
+ 'Authorization' => "Bearer #{no_admin_token}"
118
+ }
119
+
120
+ params[:aggregateFieldName] = 'foo'
121
+ Rails.cache.delete('forest.stats')
122
+ allow_any_instance_of(ForestLiana::StatsController).to receive(:find_resource).and_return(Product)
123
+ data = ForestLiana::Model::Stat.new(value: { countCurrent: 0, countPrevious: 0 })
124
+ allow_any_instance_of(ForestLiana::ValueStatGetter).to receive(:record) { data }
78
125
  # NOTICE: bypass : find_resource error
79
126
  allow_any_instance_of(ForestLiana::StatsController).to receive(:find_resource) { true }
127
+ allow(ForestLiana::QueryHelper).to receive(:get_one_association_names_symbol) { true }
128
+
129
+
130
+ post '/forest/stats/Products', params: JSON.dump(params), headers: no_admin_headers
80
131
 
81
- post '/forest/stats/Products', params: JSON.dump(params), headers: headers
82
132
  expect(response.status).to eq(403)
83
133
  end
84
134
  end
85
135
 
86
136
  describe 'POST /stats' do
87
- params = { query: 'SELECT COUNT(*) AS value FROM products;' }
137
+ params = { type: 'Value', query: 'SELECT COUNT(*) AS value FROM products;' }
88
138
 
89
139
  it 'should respond 200' do
140
+ allow_any_instance_of(ForestLiana::StatsController).to receive(:find_resource).and_return(Product)
90
141
  data = ForestLiana::Model::Stat.new(value: { value: 0, objective: 0 })
91
142
  allow_any_instance_of(ForestLiana::QueryStatGetter).to receive(:record) { data }
92
143
 
@@ -100,18 +151,28 @@ describe "Stats", type: :request do
100
151
  end
101
152
 
102
153
  it 'should respond 403 Forbidden' do
103
- allow_any_instance_of(ForestLiana::PermissionsChecker).to receive(:is_authorized?) { false }
104
-
105
- post '/forest/stats', params: JSON.dump(params), headers: headers
154
+ no_admin_token = JWT.encode({
155
+ id: 1,
156
+ email: 'michael.kelso@that70.show',
157
+ first_name: 'Michael',
158
+ last_name: 'Kelso',
159
+ team: 'Operations',
160
+ rendering_id: '16',
161
+ exp: Time.now.to_i + 2.weeks.to_i,
162
+ permission_level: 'user'
163
+ }, ForestLiana.auth_secret, 'HS256')
164
+
165
+ no_admin_headers = {
166
+ 'Accept' => 'application/json',
167
+ 'Content-Type' => 'application/json',
168
+ 'Authorization' => "Bearer #{no_admin_token}"
169
+ }
170
+ params[:query] = 'SELECT COUNT(*) AS value FROM trees;'
171
+ Rails.cache.delete('forest.stats')
172
+ allow_any_instance_of(ForestLiana::StatsController).to receive(:find_resource).and_return(Product)
173
+
174
+ post '/forest/stats', params: JSON.dump(params), headers: no_admin_headers
106
175
  expect(response.status).to eq(403)
107
176
  end
108
-
109
- it 'should respond 422 with unprocessable query' do
110
- allow_any_instance_of(ForestLiana::QueryStatGetter).to receive(:perform) { raise ForestLiana::Errors::LiveQueryError.new }
111
-
112
- post '/forest/stats', params: JSON.dump(params), headers: headers
113
- expect(response.status).to eq(422)
114
- end
115
177
  end
116
-
117
178
  end
@@ -0,0 +1,48 @@
1
+ module ForestLiana
2
+ module Ability
3
+ describe Ability do
4
+ let(:dummy_class) { Class.new { extend ForestLiana::Ability } }
5
+ let(:user) { { 'id' => '1', 'roleId' => '1' } }
6
+
7
+ before do
8
+ Island.create!(name: "L'île de la muerta")
9
+ end
10
+
11
+ describe 'forest authorize' do
12
+ it 'should call is_crud_authorized? when the action is in [browse read edit add delete export] list' do
13
+ allow_any_instance_of(ForestLiana::Ability::Permission).to receive(:is_crud_authorized?).and_return(true)
14
+ %w[browse read edit add delete export].each do |action|
15
+ expect(dummy_class.forest_authorize!(action, :user, Island.first)).to equal nil
16
+ end
17
+ end
18
+
19
+ it 'should call is_chart_authorized? when the action equal chart' do
20
+ allow_any_instance_of(ForestLiana::Ability::Permission).to receive(:is_chart_authorized?).and_return(true)
21
+ expect(dummy_class.forest_authorize!('chart', :user, Island.first, {parameters: []})).to equal nil
22
+ end
23
+
24
+ it 'should raise error 422 on a chart action when the argument parameter is nil' do
25
+ expect { dummy_class.forest_authorize!('chart', :user, Island.first) }.to raise_error(ForestLiana::Errors::HTTP422Error, "The argument parameters is missing")
26
+ end
27
+
28
+ it 'should call is_smart_action_authorized? when the action equal action' do
29
+ allow_any_instance_of(ForestLiana::Ability::Permission).to receive(:is_smart_action_authorized?).and_return(true)
30
+ expect(dummy_class.forest_authorize!('action', :user, Island.first, {parameters: [], endpoint: '...', http_method: 'POST'})).to equal true
31
+ end
32
+
33
+ it 'should raise error 422 on a chart smart-action when one or many arguments are missing' do
34
+ expect { dummy_class.forest_authorize!('action', :user, Island.first) }.to raise_error(ForestLiana::Errors::HTTP422Error, "You must implement the arguments : parameters, endpoint & http_method")
35
+ end
36
+
37
+ it 'should raise access denied when the action is unknown' do
38
+ expect { dummy_class.forest_authorize!('unknown', :user, Island.first) }.to raise_error(ForestLiana::Ability::Exceptions::AccessDenied, "You don't have permission to access this resource")
39
+ end
40
+
41
+ it 'should authorized user with correct permission_level to access charts' do
42
+ user['permission_level'] = 'admin'
43
+ expect(dummy_class.forest_authorize!('chart', user, Island.first, {parameters: []})).to equal nil
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,357 @@
1
+ module ForestLiana
2
+ module Ability
3
+ # include ForestLiana::Ability::Permission
4
+ describe Ability do
5
+ let(:user) { { 'id' => 1, 'roleId' => 1, 'rendering_id' => 1 } }
6
+ let(:action) {
7
+ {
8
+ 'triggerEnabled' => [],
9
+ 'triggerConditions' => [],
10
+ 'approvalRequired' => [],
11
+ 'approvalRequiredConditions' => [],
12
+ 'userApprovalEnabled' => [],
13
+ 'userApprovalConditions' => [],
14
+ 'selfApprovalEnabled' => []
15
+ }
16
+ }
17
+
18
+ let(:params) {
19
+ {
20
+ 'data' => {
21
+ 'attributes' => {
22
+ 'values': {},
23
+ 'ids': [
24
+ '1'
25
+ ],
26
+ 'collection_name': 'Island',
27
+ 'parent_collection_name': nil,
28
+ 'parent_collection_id': nil,
29
+ 'parent_association_name': nil,
30
+ 'all_records': false,
31
+ 'all_records_subset_query': {
32
+ 'fields[Island]': 'is,name',
33
+ 'fields[file_attachment]': 'name',
34
+ 'fields[file_blob]': 'id',
35
+ 'page[number]': 1,
36
+ 'page[size]': 15,
37
+ 'sort': '-id',
38
+ 'timezone': 'Europe/Paris'
39
+ },
40
+ 'all_records_ids_excluded': [],
41
+ 'smart_action_id': 'Island-my_action',
42
+ 'signed_approval_request': nil
43
+ }
44
+ }
45
+ }
46
+ }
47
+
48
+ before do
49
+ Island.create!(name: "foo")
50
+ end
51
+
52
+ describe 'can_execute with triggerEnabled' do
53
+ it 'should return true if triggerConditions is empty and user can trigger' do
54
+ parameters = ActionController::Parameters.new(params).permit!
55
+ action['triggerEnabled'] = [1]
56
+ smart_action_checker = ForestLiana::Ability::Permission::SmartActionChecker.new(parameters, Island, action, user)
57
+
58
+ expect(smart_action_checker.can_execute?).to equal true
59
+ end
60
+
61
+ it 'should return true if match triggerConditions and user can trigger' do
62
+ parameters = ActionController::Parameters.new(params).permit!
63
+ action['triggerEnabled'] = [1]
64
+ action['triggerConditions'] = [
65
+ { 'filter' =>
66
+ { 'aggregator' => 'and',
67
+ 'conditions' =>
68
+ [
69
+ {
70
+ 'field' => 'name',
71
+ 'value' => 'foo',
72
+ 'source' => 'data',
73
+ 'operator' => 'equal'
74
+ }
75
+ ]
76
+ },
77
+ 'roleId' => 1
78
+ }
79
+ ]
80
+ smart_action_checker = ForestLiana::Ability::Permission::SmartActionChecker.new(parameters, Island, action, user)
81
+
82
+ expect(smart_action_checker.can_execute?).to equal true
83
+ end
84
+
85
+ it 'should return true if match triggerConditions on allRecords and user can trigger' do
86
+ params['data']['attributes']['all_records'] = true
87
+ parameters = ActionController::Parameters.new(params).permit!
88
+ action['triggerEnabled'] = [1]
89
+ action['triggerConditions'] = [
90
+ { 'filter' =>
91
+ { 'aggregator' => 'and',
92
+ 'conditions' =>
93
+ [
94
+ {
95
+ 'field' => 'name',
96
+ 'value' => 'foo',
97
+ 'source' => 'data',
98
+ 'operator' => 'equal'
99
+ }
100
+ ]
101
+ },
102
+ 'roleId' => 1
103
+ }
104
+ ]
105
+ smart_action_checker = ForestLiana::Ability::Permission::SmartActionChecker.new(parameters, Island, action, user)
106
+
107
+ expect(smart_action_checker.can_execute?).to equal true
108
+ end
109
+
110
+ it 'should raise error when user can not trigger' do
111
+ parameters = ActionController::Parameters.new(params).permit!
112
+ action['triggerEnabled'] = [2]
113
+ smart_action_checker = ForestLiana::Ability::Permission::SmartActionChecker.new(parameters, Island, action, user)
114
+
115
+ expect{smart_action_checker.can_execute?}.to raise_error(ForestLiana::Ability::Exceptions::TriggerForbidden)
116
+ end
117
+
118
+ it 'should raise error when triggerConditions not match' do
119
+ parameters = ActionController::Parameters.new(params).permit!
120
+ action['triggerEnabled'] = [1]
121
+ action['triggerConditions'] = [
122
+ { 'filter' =>
123
+ { 'aggregator' => 'and',
124
+ 'conditions' =>
125
+ [
126
+ {
127
+ 'field' => 'name',
128
+ 'value' => 'fake island',
129
+ 'source' => 'data',
130
+ 'operator' => 'equal'
131
+ }
132
+ ]
133
+ },
134
+ 'roleId' => 1
135
+ }
136
+ ]
137
+ smart_action_checker = ForestLiana::Ability::Permission::SmartActionChecker.new(parameters, Island, action, user)
138
+
139
+ expect{smart_action_checker.can_execute?}.to raise_error ForestLiana::Ability::Exceptions::TriggerForbidden
140
+ end
141
+
142
+ it 'should raise error when conditions is on an unknown field' do
143
+ parameters = ActionController::Parameters.new(params).permit!
144
+ action['triggerEnabled'] = [1]
145
+ action['triggerConditions'] = [
146
+ { 'filter' =>
147
+ { 'aggregator' => 'and',
148
+ 'conditions' =>
149
+ [
150
+ {
151
+ 'field' => 'unknown-field',
152
+ 'value' => 'fake island',
153
+ 'source' => 'data',
154
+ 'operator' => 'equal'
155
+ }
156
+ ]
157
+ },
158
+ 'roleId' => 1
159
+ }
160
+ ]
161
+ smart_action_checker = ForestLiana::Ability::Permission::SmartActionChecker.new(parameters, Island, action, user)
162
+
163
+ expect{smart_action_checker.can_execute?}.to raise_error ForestLiana::Ability::Exceptions::ActionConditionError
164
+ end
165
+ end
166
+
167
+ describe 'can_execute with approvalRequired' do
168
+ it 'should raise RequireApproval error if approvalRequiredConditions is empty' do
169
+ parameters = ActionController::Parameters.new(params).permit!
170
+ action['approvalRequired'] = [1]
171
+ smart_action_checker = ForestLiana::Ability::Permission::SmartActionChecker.new(parameters, Island, action, user)
172
+
173
+ expect{smart_action_checker.can_execute?}.to raise_error ForestLiana::Ability::Exceptions::RequireApproval
174
+ end
175
+
176
+ it 'should raise RequireApproval error if match approvalRequiredConditions' do
177
+ parameters = ActionController::Parameters.new(params).permit!
178
+ action['approvalRequired'] = [1]
179
+ action['approvalRequiredConditions'] = [
180
+ { 'filter' =>
181
+ { 'aggregator' => 'and',
182
+ 'conditions' =>
183
+ [
184
+ {
185
+ 'field' => 'name',
186
+ 'value' => 'foo',
187
+ 'source' => 'data',
188
+ 'operator' => 'equal'
189
+ }
190
+ ]
191
+ },
192
+ 'roleId' => 1
193
+ }
194
+ ]
195
+ smart_action_checker = ForestLiana::Ability::Permission::SmartActionChecker.new(parameters, Island, action, user)
196
+
197
+ expect{smart_action_checker.can_execute?}.to raise_error ForestLiana::Ability::Exceptions::RequireApproval
198
+ end
199
+
200
+ it 'should raise error when user can not trigger' do
201
+ parameters = ActionController::Parameters.new(params).permit!
202
+ action['approvalRequired'] = [2]
203
+ smart_action_checker = ForestLiana::Ability::Permission::SmartActionChecker.new(parameters, Island, action, user)
204
+
205
+ expect{smart_action_checker.can_execute?}.to raise_error(ForestLiana::Ability::Exceptions::TriggerForbidden)
206
+ end
207
+
208
+ it 'should raise error when triggerConditions not match' do
209
+ parameters = ActionController::Parameters.new(params).permit!
210
+ action['approvalRequired'] = [1]
211
+ action['approvalRequiredConditions'] = [
212
+ { 'filter' =>
213
+ { 'aggregator' => 'and',
214
+ 'conditions' =>
215
+ [
216
+ {
217
+ 'field' => 'name',
218
+ 'value' => 'fake island',
219
+ 'source' => 'data',
220
+ 'operator' => 'equal'
221
+ }
222
+ ]
223
+ },
224
+ 'roleId' => 1
225
+ }
226
+ ]
227
+ smart_action_checker = ForestLiana::Ability::Permission::SmartActionChecker.new(parameters, Island, action, user)
228
+
229
+ expect{smart_action_checker.can_execute?}.to raise_error ForestLiana::Ability::Exceptions::TriggerForbidden
230
+ end
231
+ end
232
+
233
+ describe 'can_execute with userApproval' do
234
+ before do
235
+ params['data']['attributes']['requester_id'] = 2
236
+ request = params
237
+ params['data']['attributes']['signed_approval_request'] = JWT::encode(request, ForestLiana.env_secret)
238
+ action['userApprovalEnabled'] = [1]
239
+ end
240
+
241
+ it 'should return true if userApprovalConditions is empty and user has userApprovalEnabled permission' do
242
+ parameters = ActionController::Parameters.new(params).permit!
243
+ smart_action_checker = ForestLiana::Ability::Permission::SmartActionChecker.new(parameters, Island, action, user)
244
+
245
+ expect(smart_action_checker.can_execute?).to equal true
246
+ end
247
+
248
+ it 'should return true when record match userApprovalConditions and requester_id different of current user id' do
249
+ action['userApprovalConditions'] = [
250
+ { 'filter' =>
251
+ { 'aggregator' => 'and',
252
+ 'conditions' =>
253
+ [
254
+ {
255
+ 'field' => 'name',
256
+ 'value' => 'foo',
257
+ 'source' => 'data',
258
+ 'operator' => 'equal'
259
+ }
260
+ ]
261
+ },
262
+ 'roleId' => 1
263
+ }
264
+ ]
265
+ parameters = ActionController::Parameters.new(params).permit!
266
+ smart_action_checker = ForestLiana::Ability::Permission::SmartActionChecker.new(parameters, Island, action, user)
267
+
268
+ expect(smart_action_checker.can_execute?).to equal true
269
+ end
270
+
271
+ it 'should return true when record match userApprovalConditions and user can self approve' do
272
+ action['userApprovalConditions'] = [
273
+ { 'filter' =>
274
+ { 'aggregator' => 'and',
275
+ 'conditions' =>
276
+ [
277
+ {
278
+ 'field' => 'name',
279
+ 'value' => 'foo',
280
+ 'source' => 'data',
281
+ 'operator' => 'equal'
282
+ }
283
+ ]
284
+ },
285
+ 'roleId' => 1
286
+ }
287
+ ]
288
+ action['selfApprovalEnabled'] = [1]
289
+ params['data']['attributes']['requester_id'] = 2
290
+ request = params
291
+ params['data']['attributes']['signed_approval_request'] = JWT::encode(request, ForestLiana.env_secret)
292
+ parameters = ActionController::Parameters.new(params).permit!
293
+ smart_action_checker = ForestLiana::Ability::Permission::SmartActionChecker.new(parameters, Island, action, user)
294
+
295
+ expect(smart_action_checker.can_execute?).to equal true
296
+ end
297
+
298
+ it 'should raise error when user has userApprovalEnabled permission' do
299
+ parameters = ActionController::Parameters.new(params).permit!
300
+ action['userApprovalEnabled'] = [2]
301
+ smart_action_checker = ForestLiana::Ability::Permission::SmartActionChecker.new(parameters, Island, action, user)
302
+
303
+ expect{smart_action_checker.can_execute?}.to raise_error(ForestLiana::Ability::Exceptions::TriggerForbidden)
304
+ end
305
+
306
+ it 'should raise error when triggerConditions not match' do
307
+ parameters = ActionController::Parameters.new(params).permit!
308
+ action['userApprovalConditions'] = [
309
+ { 'filter' =>
310
+ { 'aggregator' => 'and',
311
+ 'conditions' =>
312
+ [
313
+ {
314
+ 'field' => 'name',
315
+ 'value' => 'fake island',
316
+ 'source' => 'data',
317
+ 'operator' => 'equal'
318
+ }
319
+ ]
320
+ },
321
+ 'roleId' => 1
322
+ }
323
+ ]
324
+ smart_action_checker = ForestLiana::Ability::Permission::SmartActionChecker.new(parameters, Island, action, user)
325
+
326
+ expect{smart_action_checker.can_execute?}.to raise_error(ForestLiana::Ability::Exceptions::TriggerForbidden)
327
+ end
328
+
329
+ it 'should raise error when requester_id equal to current user id without selfApprove permission' do
330
+ action['userApprovalConditions'] = [
331
+ { 'filter' =>
332
+ { 'aggregator' => 'and',
333
+ 'conditions' =>
334
+ [
335
+ {
336
+ 'field' => 'name',
337
+ 'value' => 'foo',
338
+ 'source' => 'data',
339
+ 'operator' => 'equal'
340
+ }
341
+ ]
342
+ },
343
+ 'roleId' => 1
344
+ }
345
+ ]
346
+ params['data']['attributes']['requester_id'] = 1
347
+ request = params
348
+ params['data']['attributes']['signed_approval_request'] = JWT::encode(request, ForestLiana.env_secret)
349
+ parameters = ActionController::Parameters.new(params).permit!
350
+ smart_action_checker = ForestLiana::Ability::Permission::SmartActionChecker.new(parameters, Island, action, user)
351
+
352
+ expect{smart_action_checker.can_execute?}.to raise_error(ForestLiana::Ability::Exceptions::TriggerForbidden)
353
+ end
354
+ end
355
+ end
356
+ end
357
+ end