forest_liana 5.3.3 → 5.4.0

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.
@@ -32,9 +32,10 @@ module ForestLiana
32
32
  def compute_condition_filters_from_scope(user_id)
33
33
  computed_condition_filters = @scope_filters.clone
34
34
  computed_condition_filters['conditions'].each do |condition|
35
- if condition.include?('value') &&
36
- !condition['value'].nil? &&
37
- condition['value'].start_with?('$') &&
35
+ if condition.include?('value') &&
36
+ !condition['value'].nil? &&
37
+ condition['value'].instance_of?(String) &&
38
+ condition['value'].start_with?('$') &&
38
39
  @users_variable_values.include?(user_id)
39
40
  condition['value'] = @users_variable_values[user_id][condition['value']]
40
41
  end
@@ -51,9 +52,9 @@ module ForestLiana
51
52
  ensure_valid_aggregation(node)
52
53
 
53
54
  return is_scope_condition?(node) unless node['aggregator']
54
-
55
+
55
56
  # NOTICE: Remove conditions that are not from the scope
56
- filtered_conditions = node['conditions'].map { |condition|
57
+ filtered_conditions = node['conditions'].map { |condition|
57
58
  search_scope_aggregation(condition)
58
59
  }.select { |condition|
59
60
  condition
@@ -61,7 +62,7 @@ module ForestLiana
61
62
 
62
63
  # NOTICE: If there is only one condition filter left and its current aggregator is
63
64
  # an "and", this condition filter is the searched scope
64
- if (filtered_conditions.length == 1 &&
65
+ if (filtered_conditions.length == 1 &&
65
66
  filtered_conditions.first.is_a?(Hash) &&
66
67
  filtered_conditions.first.include?(:aggregator) &&
67
68
  node['aggregator'] == 'and')
@@ -70,7 +71,7 @@ module ForestLiana
70
71
 
71
72
  # NOTICE: Otherwise, validate if the current node is the scope and return nil
72
73
  # if it's not
73
- return (filtered_conditions.length == @scope_filters['conditions'].length &&
74
+ return (filtered_conditions.length == @scope_filters['conditions'].length &&
74
75
  node['aggregator'] == @scope_filters['aggregator']) ?
75
76
  { aggregator: node['aggregator'], conditions: filtered_conditions } :
76
77
  nil
@@ -0,0 +1,13 @@
1
+ module ForestLiana
2
+ module Utils
3
+ class BetaSchemaUtils
4
+ def self.find_action_from_endpoint(collection_name, endpoint, http_method)
5
+ collection = ForestLiana.apimap.find { |collection| collection.name.to_s == collection_name }
6
+
7
+ return nil unless collection
8
+
9
+ collection.actions.find { |action| action.endpoint == endpoint && action.http_method == http_method }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module ForestLiana
2
- VERSION = "5.3.3"
2
+ VERSION = "5.4.0"
3
3
  end
@@ -0,0 +1,711 @@
1
+ module ForestLiana
2
+ describe PermissionsChecker do
3
+ before(:each) do
4
+ described_class.empty_cache
5
+ end
6
+
7
+ let(:user_id) { 1 }
8
+ let(:schema) {
9
+ [
10
+ ForestLiana::Model::Collection.new({
11
+ name: 'all_rights_collection',
12
+ fields: [],
13
+ actions: [
14
+ ForestLiana::Model::Action.new({
15
+ name: 'Test',
16
+ endpoint: 'forest/actions/Test',
17
+ http_method: 'POST'
18
+ }), ForestLiana::Model::Action.new({
19
+ name: 'TestPut',
20
+ endpoint: 'forest/actions/Test',
21
+ http_method: 'PUT'
22
+ }), ForestLiana::Model::Action.new({
23
+ name: 'TestRestricted',
24
+ endpoint: 'forest/actions/TestRestricted',
25
+ http_method: 'POST'
26
+ }), ForestLiana::Model::Action.new({
27
+ name: 'Test Default Values',
28
+ })
29
+ ]
30
+ }), ForestLiana::Model::Collection.new({
31
+ name: 'no_rights_collection',
32
+ fields: [],
33
+ actions: [
34
+ ForestLiana::Model::Action.new({
35
+ name: 'Test',
36
+ endpoint: 'forest/actions/Test',
37
+ http_method: 'POST'
38
+ })
39
+ ]
40
+ }), ForestLiana::Model::Collection.new({
41
+ name: 'custom',
42
+ fields: [],
43
+ actions: []
44
+ })
45
+ ]
46
+ }
47
+ let(:default_api_permissions) {
48
+ {
49
+ "data" => {
50
+ "all_rights_collection" => {
51
+ "collection" => {
52
+ "list" => true,
53
+ "show" => true,
54
+ "create" => true,
55
+ "update" => true,
56
+ "delete" => true,
57
+ "export" => true,
58
+ "searchToEdit" => true
59
+ },
60
+ "actions" => {
61
+ "Test" => {
62
+ "allowed" => true,
63
+ "users" => nil
64
+ },
65
+ "TestPut" => {
66
+ "allowed" => false,
67
+ "users" => nil
68
+ },
69
+ "TestRestricted" => {
70
+ "allowed" => true,
71
+ "users" => [1]
72
+ },
73
+ "Test Default Values" => {
74
+ "allowed" => true,
75
+ "users" => nil
76
+ },
77
+ },
78
+ "scope" => nil
79
+ },
80
+ "no_rights_collection" => {
81
+ "collection" => {
82
+ "list" => false,
83
+ "show" => false,
84
+ "create" => false,
85
+ "update" => false,
86
+ "delete" => false,
87
+ "export" => false,
88
+ "searchToEdit" => false
89
+ },
90
+ "actions" => {
91
+ "Test" => {
92
+ "allowed" => false,
93
+ "users" => nil
94
+ }
95
+ },
96
+ "scope" => nil
97
+ },
98
+ },
99
+ "meta" => {
100
+ "rolesACLActivated" => false
101
+ }
102
+ }
103
+ }
104
+
105
+ before do
106
+ allow(ForestLiana).to receive(:name_for).and_return(collection_name)
107
+ allow(ForestLiana).to receive(:apimap).and_return(schema)
108
+ end
109
+
110
+ describe 'handling cache' do
111
+ let(:collection_name) { 'all_rights_collection' }
112
+ let(:fake_ressource) { nil }
113
+ let(:default_rendering_id) { 1 }
114
+
115
+ context 'when calling twice the same permissions' do
116
+ before do
117
+ # clones is called to duplicate the returned value and not use to same (which results in an error
118
+ # as the permissions is edited through the formatter)
119
+ allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering) { default_api_permissions.clone }
120
+ end
121
+
122
+ context 'after expiration time' do
123
+ before do
124
+ allow(ENV).to receive(:[]).with('FOREST_PERMISSIONS_EXPIRATION_IN_SECONDS').and_return('-1')
125
+ # Needed to enforce ENV stub
126
+ described_class.empty_cache
127
+ end
128
+
129
+ it 'should call the API twice' do
130
+ described_class.new(fake_ressource, 'exportEnabled', default_rendering_id, user_id: user_id).is_authorized?
131
+ described_class.new(fake_ressource, 'exportEnabled', default_rendering_id, user_id: user_id).is_authorized?
132
+
133
+ expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).twice
134
+ end
135
+ end
136
+
137
+ context 'before expiration time' do
138
+ it 'should call the API only once' do
139
+ described_class.new(fake_ressource, 'exportEnabled', default_rendering_id, user_id: user_id).is_authorized?
140
+ described_class.new(fake_ressource, 'exportEnabled', default_rendering_id, user_id: user_id).is_authorized?
141
+
142
+ expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).once
143
+ end
144
+ end
145
+ end
146
+
147
+ context 'with permissions coming from 2 different renderings' do
148
+ let(:collection_name) { 'custom' }
149
+ let(:api_permissions_rendering_1) {
150
+ {
151
+ "data" => {
152
+ "custom" => {
153
+ "collection" => {
154
+ "list" => true,
155
+ "show" => true,
156
+ "create" => true,
157
+ "update" => true,
158
+ "delete" => true,
159
+ "export" => true,
160
+ "searchToEdit" => true
161
+ },
162
+ "actions" => { },
163
+ "scope" => nil
164
+ },
165
+ },
166
+ "meta" => {
167
+ "rolesACLActivated" => false
168
+ }
169
+ }
170
+ }
171
+ let(:api_permissions_rendering_2) {
172
+ api_permissions_rendering_2 = api_permissions_rendering_1.deep_dup
173
+ api_permissions_rendering_2['data']['custom']['collection']['export'] = false
174
+ api_permissions_rendering_2
175
+ }
176
+ let(:authorized_to_export_rendering_1) { described_class.new(fake_ressource, 'exportEnabled', 1, user_id: user_id).is_authorized? }
177
+ let(:authorized_to_export_rendering_2) { described_class.new(fake_ressource, 'exportEnabled', 2, user_id: user_id).is_authorized? }
178
+
179
+ before do
180
+ allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering)
181
+ allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(1).and_return(api_permissions_rendering_1)
182
+ allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(2).and_return(api_permissions_rendering_2)
183
+ end
184
+
185
+ it 'should return 2 different values' do
186
+ expect(authorized_to_export_rendering_1).to eq true
187
+ expect(authorized_to_export_rendering_2).to eq false
188
+ end
189
+ end
190
+ end
191
+
192
+
193
+ context 'scopes cache' do
194
+ let(:fake_ressource) { nil }
195
+ let(:rendering_id) { 1 }
196
+ let(:collection_name) { 'custom' }
197
+ let(:scope_permissions) { { rendering_id => { 'custom' => nil } } }
198
+ let(:api_permissions) {
199
+ {
200
+ "data" => {
201
+ "custom" => {
202
+ "collection" => {
203
+ "list" => true,
204
+ "show" => true,
205
+ "create" => true,
206
+ "update" => true,
207
+ "delete" => true,
208
+ "export" => true,
209
+ "searchToEdit" => true
210
+ },
211
+ "actions" => { },
212
+ "scope" => nil
213
+ },
214
+ },
215
+ "meta" => {
216
+ "rolesACLActivated" => false
217
+ }
218
+ }
219
+ }
220
+ let(:api_permissions_scope_only) {
221
+ {
222
+ "data" => {
223
+ 'collections' => { },
224
+ 'renderings' => scope_permissions
225
+ },
226
+ "meta" => {
227
+ "rolesACLActivated" => false
228
+ }
229
+ }
230
+ }
231
+
232
+ before do
233
+ # clones is called to duplicate the returned value and not use to same (which results in an error
234
+ # as the permissions is edited through the formatter)
235
+ allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(rendering_id) { api_permissions.clone }
236
+ allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(rendering_id, rendering_specific_only: true).and_return(api_permissions_scope_only)
237
+ end
238
+
239
+ context 'when checking once for authorization' do
240
+ context 'when checking browseEnabled' do
241
+ context 'when expiration value is set to its default' do
242
+ it 'should not call the API to refresh the scopes cache' do
243
+ described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
244
+
245
+ expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id).once
246
+ expect(ForestLiana::PermissionsGetter).not_to have_received(:get_permissions_for_rendering).with(rendering_id, rendering_specific_only: true)
247
+ end
248
+ end
249
+
250
+ context 'when expiration value is set in the past' do
251
+ before do
252
+ allow(ENV).to receive(:[]).with('FOREST_PERMISSIONS_EXPIRATION_IN_SECONDS').and_return('-1')
253
+ # Needed to enforce ENV stub
254
+ described_class.empty_cache
255
+ end
256
+
257
+ it 'should call the API to refresh the scopes cache' do
258
+ described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
259
+
260
+ expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id).once
261
+ expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id, rendering_specific_only: true).once
262
+ end
263
+ end
264
+ end
265
+
266
+ # Only browse permission requires scopes
267
+ context 'when checking exportEnabled' do
268
+ context 'when expiration value is set in the past' do
269
+ before do
270
+ allow(ENV).to receive(:[]).with('FOREST_PERMISSIONS_EXPIRATION_IN_SECONDS').and_return('-1')
271
+ # Needed to enforce ENV stub
272
+ described_class.empty_cache
273
+ end
274
+ end
275
+
276
+ it 'should NOT call the API to refresh the scopes cache' do
277
+ described_class.new(fake_ressource, 'exportEnabled', rendering_id, user_id: user_id).is_authorized?
278
+
279
+ expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id).once
280
+ expect(ForestLiana::PermissionsGetter).not_to have_received(:get_permissions_for_rendering).with(rendering_id, rendering_specific_only: true)
281
+ end
282
+ end
283
+ end
284
+
285
+ context 'when checking twice for authorization' do
286
+ context 'on the same rendering' do
287
+ context 'when scopes permission has NOT expired' do
288
+ it 'should NOT call the API to refresh the scopes permissions' do
289
+ described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
290
+ described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
291
+
292
+ expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id).once
293
+ expect(ForestLiana::PermissionsGetter).not_to have_received(:get_permissions_for_rendering).with(rendering_id, rendering_specific_only: true)
294
+ end
295
+ end
296
+
297
+ context 'when scopes permission has expired' do
298
+ before do
299
+ allow(ENV).to receive(:[]).with('FOREST_PERMISSIONS_EXPIRATION_IN_SECONDS').and_return('-1')
300
+ # Needed to enforce ENV stub
301
+ described_class.empty_cache
302
+ end
303
+
304
+ it 'should call the API to refresh the scopes permissions' do
305
+ described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
306
+ described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
307
+
308
+ expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id).twice
309
+ expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id, rendering_specific_only: true).twice
310
+ end
311
+ end
312
+ end
313
+
314
+ context 'on two different renderings' do
315
+ let(:other_rendering_id) { 2 }
316
+ let(:api_permissions_scope_only) {
317
+ {
318
+ "data" => {
319
+ 'collections' => { },
320
+ 'renderings' => {
321
+ '2' => { 'custom' => nil }
322
+ }
323
+ },
324
+ "meta" => {
325
+ "rolesACLActivated" => false
326
+ }
327
+ }
328
+ }
329
+ let(:api_permissions_copy) { api_permissions.clone }
330
+
331
+ before do
332
+ allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(other_rendering_id).and_return(api_permissions_copy)
333
+ allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(other_rendering_id, rendering_specific_only: true).and_return(api_permissions_scope_only)
334
+ end
335
+
336
+ it 'should not call the API to refresh the scopes permissions' do
337
+ described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
338
+ described_class.new(fake_ressource, 'browseEnabled', other_rendering_id, user_id: user_id).is_authorized?
339
+
340
+ expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id).once
341
+ expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(other_rendering_id).once
342
+ expect(ForestLiana::PermissionsGetter).not_to have_received(:get_permissions_for_rendering).with(rendering_id, rendering_specific_only: true)
343
+ expect(ForestLiana::PermissionsGetter).not_to have_received(:get_permissions_for_rendering).with(other_rendering_id, rendering_specific_only: true)
344
+ end
345
+ end
346
+ end
347
+ end
348
+
349
+ describe '#is_authorized?' do
350
+ # Resource is only used to retrieve the collection name as it's stubbed it does not
351
+ # need to be defined
352
+ let(:fake_ressource) { nil }
353
+ let(:default_rendering_id) { nil }
354
+ let(:api_permissions) { default_api_permissions }
355
+ let(:collection_name) { 'all_rights_collection' }
356
+
357
+ before do
358
+ allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).and_return(api_permissions)
359
+ end
360
+
361
+ context 'when permissions does NOT have rolesACLActivated' do
362
+ describe 'exportEnabled permission' do
363
+ subject { described_class.new(fake_ressource, 'exportEnabled', default_rendering_id, user_id: user_id) }
364
+
365
+ context 'when user has the required permission' do
366
+ it 'should be authorized' do
367
+ expect(subject.is_authorized?).to be true
368
+ end
369
+ end
370
+
371
+ context 'when user has not the required permission' do
372
+ let(:collection_name) { 'no_rights_collection' }
373
+
374
+ it 'should NOT be authorized' do
375
+ expect(subject.is_authorized?).to be false
376
+ end
377
+ end
378
+ end
379
+
380
+ describe 'browseEnabled permission' do
381
+ let(:collection_name) { 'custom' }
382
+ subject { described_class.new(fake_ressource, 'browseEnabled', default_rendering_id, user_id: user_id) }
383
+ let(:scope_permissions) { nil }
384
+ let(:default_api_permissions) {
385
+ {
386
+ "data" => {
387
+ "custom" => {
388
+ "collection" => collection_permissions,
389
+ "actions" => { },
390
+ "scope" => scope_permissions
391
+ },
392
+ },
393
+ "meta" => {
394
+ "rolesACLActivated" => false
395
+ }
396
+ }
397
+ }
398
+
399
+ context 'when user has list permission' do
400
+ let(:collection_permissions) {
401
+ {
402
+ "list" => true,
403
+ "show" => false,
404
+ "create" => false,
405
+ "update" => false,
406
+ "delete" => false,
407
+ "export" => false,
408
+ "searchToEdit" => false
409
+ }
410
+ }
411
+
412
+ it 'should be authorized' do
413
+ expect(subject.is_authorized?).to be true
414
+ end
415
+ end
416
+
417
+ context 'when user has searchToEdit permission' do
418
+ let(:collection_permissions) {
419
+ {
420
+ "list" => false,
421
+ "show" => false,
422
+ "create" => false,
423
+ "update" => false,
424
+ "delete" => false,
425
+ "export" => false,
426
+ "searchToEdit" => true
427
+ }
428
+ }
429
+
430
+ it 'should be authorized' do
431
+ expect(subject.is_authorized?).to be true
432
+ end
433
+ end
434
+
435
+ context 'when user has not the list nor the searchToEdit permission' do
436
+ let(:collection_permissions) {
437
+ {
438
+ "list" => false,
439
+ "show" => false,
440
+ "create" => false,
441
+ "update" => false,
442
+ "delete" => false,
443
+ "export" => false,
444
+ "searchToEdit" => false
445
+ }
446
+ }
447
+
448
+ it 'should be NOT authorized' do
449
+ expect(subject.is_authorized?).to be false
450
+ end
451
+ end
452
+
453
+ context 'when providing collection_list_parameters' do
454
+ let(:collection_permissions) {
455
+ {
456
+ "list" => true,
457
+ "show" => false,
458
+ "create" => false,
459
+ "update" => false,
460
+ "delete" => false,
461
+ "export" => false,
462
+ "searchToEdit" => false
463
+ }
464
+ }
465
+ let(:collection_list_parameters) { { :user_id => "1", :filters => nil } }
466
+
467
+ subject {
468
+ described_class.new(
469
+ fake_ressource,
470
+ 'browseEnabled',
471
+ default_rendering_id,
472
+ user_id: user_id,
473
+ collection_list_parameters: collection_list_parameters
474
+ )
475
+ }
476
+
477
+ context 'when user has the required permission' do
478
+ it 'should be authorized' do
479
+ expect(subject.is_authorized?).to be true
480
+ end
481
+ end
482
+
483
+ context 'when user has not the required permission' do
484
+ let(:collection_permissions) {
485
+ {
486
+ "list" => false,
487
+ "show" => false,
488
+ "create" => false,
489
+ "update" => false,
490
+ "delete" => false,
491
+ "export" => false,
492
+ "searchToEdit" => false
493
+ }
494
+ }
495
+
496
+ it 'should NOT be authorized' do
497
+ expect(subject.is_authorized?).to be false
498
+ end
499
+ end
500
+
501
+ context 'when scopes are defined' do
502
+ let(:scope_permissions) { { 'dynamicScopesValues' => {}, 'filter' => { 'aggregator' => 'and', 'conditions' => [condition] } }}
503
+ let(:collection_list_parameters) { { :user_id => "1", :filters => JSON.generate(condition) } }
504
+
505
+ context 'when scopes are passing validation' do
506
+ context 'when scope value is a string' do
507
+ let(:condition) { { 'field' => 'field_1', 'operator' => 'equal', 'value' => true } }
508
+
509
+ it 'should return true' do
510
+ expect(subject.is_authorized?).to be true
511
+ end
512
+ end
513
+
514
+ context 'when scope value is a boolean' do
515
+ let(:condition) { { 'field' => 'field_1', 'operator' => 'equal', 'value' => 'true' } }
516
+
517
+ it 'should return true' do
518
+ expect(subject.is_authorized?).to be true
519
+ end
520
+ end
521
+ end
522
+
523
+ context 'when scopes are NOT passing validation' do
524
+ let(:condition) { { 'field' => 'field_1', 'operator' => 'equal', 'value' => true } }
525
+ let(:other_condition) {
526
+ {
527
+ aggregator: 'and',
528
+ conditions: [
529
+ { field: 'name', value: 'john', operator: 'equal' },
530
+ { field: 'price', value: '2500', operator: 'equal' }
531
+ ]
532
+ }
533
+ }
534
+ let(:collection_list_parameters) {
535
+ {
536
+ :user_id => "1",
537
+ :filters => JSON.generate(other_condition)
538
+ }
539
+ }
540
+
541
+
542
+ it 'should return false' do
543
+ expect(subject.is_authorized?).to be false
544
+ end
545
+ end
546
+ end
547
+ end
548
+ end
549
+
550
+ describe 'readEnabled permission' do
551
+ subject { described_class.new(fake_ressource, 'readEnabled', default_rendering_id, user_id: user_id) }
552
+
553
+ context 'when user has the required permission' do
554
+ it 'should be authorized' do
555
+ expect(subject.is_authorized?).to be true
556
+ end
557
+ end
558
+
559
+ context 'when user has not the required permission' do
560
+ let(:collection_name) { 'no_rights_collection' }
561
+
562
+ it 'should NOT be authorized' do
563
+ expect(subject.is_authorized?).to be false
564
+ end
565
+ end
566
+ end
567
+
568
+ describe 'addEnabled permission' do
569
+ subject { described_class.new(fake_ressource, 'addEnabled', default_rendering_id, user_id: user_id) }
570
+
571
+ context 'when user has the required permission' do
572
+ it 'should be authorized' do
573
+ expect(subject.is_authorized?).to be true
574
+ end
575
+ end
576
+
577
+ context 'when user has not the required permission' do
578
+ let(:collection_name) { 'no_rights_collection' }
579
+
580
+ it 'should NOT be authorized' do
581
+ expect(subject.is_authorized?).to be false
582
+ end
583
+ end
584
+ end
585
+
586
+ describe 'editEnabled permission' do
587
+ subject { described_class.new(fake_ressource, 'editEnabled', default_rendering_id, user_id: user_id) }
588
+
589
+ context 'when user has the required permission' do
590
+ it 'should be authorized' do
591
+ expect(subject.is_authorized?).to be true
592
+ end
593
+ end
594
+
595
+ context 'when user has not the required permission' do
596
+ let(:collection_name) { 'no_rights_collection' }
597
+
598
+ it 'should NOT be authorized' do
599
+ expect(subject.is_authorized?).to be false
600
+ end
601
+ end
602
+ end
603
+
604
+ describe 'deleteEnabled permission' do
605
+ subject { described_class.new(fake_ressource, 'deleteEnabled', default_rendering_id, user_id: user_id) }
606
+
607
+ context 'when user has the required permission' do
608
+ it 'should be authorized' do
609
+ expect(subject.is_authorized?).to be true
610
+ end
611
+ end
612
+
613
+ context 'when user has not the required permission' do
614
+ let(:collection_name) { 'no_rights_collection' }
615
+
616
+ it 'should NOT be authorized' do
617
+ expect(subject.is_authorized?).to be false
618
+ end
619
+ end
620
+ end
621
+
622
+ describe 'actions permission' do
623
+ let(:smart_action_request_info) { { endpoint: 'forest/actions/Test', http_method: 'POST' } }
624
+ subject {
625
+ described_class.new(
626
+ fake_ressource,
627
+ 'actions',
628
+ default_rendering_id,
629
+ user_id: user_id,
630
+ smart_action_request_info: smart_action_request_info
631
+ )
632
+ }
633
+
634
+ context 'when user has the required permission' do
635
+
636
+ it 'should be authorized' do
637
+ expect(subject.is_authorized?).to be true
638
+ end
639
+ end
640
+
641
+ context 'when user has not the required permission' do
642
+ let(:collection_name) { 'no_rights_collection' }
643
+
644
+ it 'should NOT be authorized' do
645
+ expect(subject.is_authorized?).to be false
646
+ end
647
+ end
648
+
649
+ context 'when endpoint is missing from smart action parameters' do
650
+ let(:smart_action_request_info) { { http_method: 'POST' } }
651
+
652
+ it 'user should NOT be authorized' do
653
+ expect(subject.is_authorized?).to be false
654
+ end
655
+ end
656
+
657
+ context 'when http_method is missing from smart action parameters' do
658
+ let(:smart_action_request_info) { { endpoint: 'forest/actions/Test' } }
659
+
660
+ it 'user should NOT be authorized' do
661
+ expect(subject.is_authorized?).to be false
662
+ end
663
+ end
664
+
665
+ context 'when the provided endpoint is not part of the schema' do
666
+ let(:smart_action_request_info) { { endpoint: 'forest/actions/Test', http_method: 'DELETE' } }
667
+
668
+ it 'user should NOT be authorized' do
669
+ expect(subject.is_authorized?).to be false
670
+ end
671
+ end
672
+
673
+ context 'when the action permissions contains a list of user ids' do
674
+ context 'when user id is NOT part of the authorized users' do
675
+ let(:user_id) { 2 }
676
+ let(:smart_action_request_info) { { endpoint: 'forest/actions/TestRestricted', http_method: 'POST' } }
677
+
678
+ it 'user should NOT be authorized' do
679
+ expect(subject.is_authorized?).to be false
680
+ end
681
+ end
682
+
683
+ context 'when user id is part of the authorized users' do
684
+ let(:smart_action_request_info) { { endpoint: 'forest/actions/TestRestricted', http_method: 'POST' } }
685
+
686
+ it 'user should be authorized' do
687
+ expect(subject.is_authorized?).to be true
688
+ end
689
+ end
690
+ end
691
+
692
+ context 'when the action has been created with default http endpoint and method in the schema' do
693
+ let(:smart_action_request_info) { { endpoint: 'forest/actions/test-default-values', http_method: 'POST' } }
694
+
695
+ it 'user should be authorized' do
696
+ expect(subject.is_authorized?).to be true
697
+ end
698
+ end
699
+
700
+ context 'when the action has the same enpoint as an other' do
701
+ let(:smart_action_request_info) { { endpoint: 'forest/actions/Test', http_method: 'PUT' } }
702
+
703
+ it 'user should NOT be authorized' do
704
+ expect(subject.is_authorized?).to be false
705
+ end
706
+ end
707
+ end
708
+ end
709
+ end
710
+ end
711
+ end