forest_liana 5.3.3 → 5.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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