forest_liana 5.2.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.
- checksums.yaml +4 -4
- data/app/controllers/forest_liana/actions_controller.rb +95 -0
- data/app/controllers/forest_liana/resources_controller.rb +14 -17
- data/app/controllers/forest_liana/smart_actions_controller.rb +10 -5
- data/app/helpers/forest_liana/is_same_data_structure_helper.rb +44 -0
- data/app/helpers/forest_liana/widgets_helper.rb +59 -0
- data/app/models/forest_liana/model/action.rb +2 -1
- data/app/services/forest_liana/apimap_sorter.rb +1 -0
- data/app/services/forest_liana/permissions_checker.rb +118 -56
- data/app/services/forest_liana/permissions_formatter.rb +52 -0
- data/app/services/forest_liana/permissions_getter.rb +52 -17
- data/app/services/forest_liana/resources_getter.rb +3 -3
- data/app/services/forest_liana/scope_validator.rb +8 -7
- data/app/services/forest_liana/utils/beta_schema_utils.rb +13 -0
- data/config/routes.rb +2 -0
- data/lib/forest_liana/bootstrapper.rb +19 -0
- data/lib/forest_liana/schema_file_updater.rb +1 -0
- data/lib/forest_liana/version.rb +1 -1
- data/spec/helpers/forest_liana/is_same_data_structure_helper_spec.rb +87 -0
- data/spec/requests/actions_controller_spec.rb +174 -0
- data/spec/services/forest_liana/apimap_sorter_spec.rb +6 -4
- data/spec/services/forest_liana/permissions_checker_acl_disabled_spec.rb +711 -0
- data/spec/services/forest_liana/permissions_checker_acl_enabled_spec.rb +831 -0
- data/spec/services/forest_liana/permissions_formatter_spec.rb +222 -0
- data/spec/services/forest_liana/permissions_getter_spec.rb +82 -0
- data/spec/services/forest_liana/schema_adapter_spec.rb +1 -1
- data/spec/spec_helper.rb +3 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e1a93b16b8c079a92000891ac73f8794fa87c2b6411e99a6e160d7f5e88e64d
|
4
|
+
data.tar.gz: 0b6853a6eda1fef9f395fa9f247b90273fef74fe8eb9e621ed4647d43832dc03
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e7aa35686573cce22819ea583a20c9d93afd39b72187aae0c618fd0e67e1494475435ae0ca9c8c892b7bbe3015c0e6ac0f220ca75b2526f66883f5a491f54f7
|
7
|
+
data.tar.gz: ffdcfcf09b90001e66bff1910a86d635def03cf718a9e13282061d4f9d5c4b0780058ba7462106ea6c4deb299e388bb3c32a3eec624d51bfd7b0420a85a60167
|
@@ -1,7 +1,102 @@
|
|
1
1
|
module ForestLiana
|
2
2
|
class ActionsController < ForestLiana::BaseController
|
3
|
+
|
3
4
|
def values
|
4
5
|
render serializer: nil, json: {}, status: :ok
|
5
6
|
end
|
7
|
+
|
8
|
+
def get_collection(collection_name)
|
9
|
+
ForestLiana.apimap.find { |collection| collection.name.to_s == collection_name }
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_action(collection_name)
|
13
|
+
collection = get_collection(collection_name)
|
14
|
+
begin
|
15
|
+
collection.actions.find {|action| ActiveSupport::Inflector.parameterize(action.name) == params[:action_name]}
|
16
|
+
rescue => error
|
17
|
+
FOREST_LOGGER.error "Smart Action get action retrieval error: #{error}"
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_record
|
23
|
+
model = ForestLiana::SchemaUtils.find_model_from_collection_name(params[:collectionName])
|
24
|
+
redord_getter = ForestLiana::ResourceGetter.new(model, {:id => params[:recordIds][0]})
|
25
|
+
redord_getter.perform
|
26
|
+
redord_getter.record
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_smart_action_load_ctx(fields)
|
30
|
+
fields = fields.reduce({}) do |p, c|
|
31
|
+
ForestLiana::WidgetsHelper.set_field_widget(c)
|
32
|
+
p.update(c[:field] => c.merge!(value: nil))
|
33
|
+
end
|
34
|
+
{:record => get_record, :fields => fields}
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_smart_action_change_ctx(fields)
|
38
|
+
fields = fields.reduce({}) do |p, c|
|
39
|
+
field = c.permit!.to_h.symbolize_keys
|
40
|
+
ForestLiana::WidgetsHelper.set_field_widget(field)
|
41
|
+
p.update(c[:field] => field)
|
42
|
+
end
|
43
|
+
{:record => get_record, :fields => fields}
|
44
|
+
end
|
45
|
+
|
46
|
+
def handle_result(result, formatted_fields, action)
|
47
|
+
if result.nil? || !result.is_a?(Hash)
|
48
|
+
return render status: 500, json: { error: 'Error in smart action load hook: hook must return an object' }
|
49
|
+
end
|
50
|
+
is_same_data_structure = ForestLiana::IsSameDataStructureHelper::Analyser.new(formatted_fields, result, 1)
|
51
|
+
unless is_same_data_structure.perform
|
52
|
+
return render status: 500, json: { error: 'Error in smart action hook: fields must be unchanged (no addition nor deletion allowed)' }
|
53
|
+
end
|
54
|
+
|
55
|
+
# Apply result on fields (transform the object back to an array), preserve order.
|
56
|
+
fields = action.fields.map do |field|
|
57
|
+
updated_field = result[field[:field]]
|
58
|
+
# Reset `value` when not present in `enums` (which means `enums` has changed).
|
59
|
+
if updated_field[:enums].is_a?(Array) && !updated_field[:enums].include?(updated_field[:value])
|
60
|
+
updated_field[:value] = nil
|
61
|
+
end
|
62
|
+
updated_field
|
63
|
+
end
|
64
|
+
|
65
|
+
render serializer: nil, json: { fields: fields}, status: :ok
|
66
|
+
end
|
67
|
+
|
68
|
+
def load
|
69
|
+
action = get_action(params[:collectionName])
|
70
|
+
|
71
|
+
if !action
|
72
|
+
render status: 500, json: {error: 'Error in smart action load hook: cannot retrieve action from collection'}
|
73
|
+
else
|
74
|
+
# Transform fields from array to an object to ease usage in hook, adds null value.
|
75
|
+
context = get_smart_action_load_ctx(action.fields)
|
76
|
+
formatted_fields = context[:fields].clone # clone for following test on is_same_data_structure
|
77
|
+
|
78
|
+
# Call the user-defined load hook.
|
79
|
+
result = action.hooks[:load].(context)
|
80
|
+
|
81
|
+
handle_result(result, formatted_fields, action)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def change
|
86
|
+
action = get_action(params[:collectionName])
|
87
|
+
|
88
|
+
if !action
|
89
|
+
render status: 500, json: {error: 'Error in smart action change hook: cannot retrieve action from collection'}
|
90
|
+
else
|
91
|
+
# Transform fields from array to an object to ease usage in hook.
|
92
|
+
context = get_smart_action_change_ctx(params[:fields])
|
93
|
+
formatted_fields = context[:fields].clone # clone for following test on is_same_data_structure
|
94
|
+
|
95
|
+
# Call the user-defined change hook.
|
96
|
+
result = action.hooks[:change][params[:changedField]].(context)
|
97
|
+
|
98
|
+
handle_result(result, formatted_fields, action)
|
99
|
+
end
|
100
|
+
end
|
6
101
|
end
|
7
102
|
end
|
@@ -16,18 +16,15 @@ module ForestLiana
|
|
16
16
|
def index
|
17
17
|
begin
|
18
18
|
if request.format == 'csv'
|
19
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, '
|
20
|
-
return head :forbidden unless checker.is_authorized?
|
21
|
-
elsif params.has_key?(:searchToEdit)
|
22
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, 'searchToEdit', @rendering_id)
|
19
|
+
checker = ForestLiana::PermissionsChecker.new(@resource, 'exportEnabled', @rendering_id, user_id: forest_user['id'])
|
23
20
|
return head :forbidden unless checker.is_authorized?
|
24
21
|
else
|
25
22
|
checker = ForestLiana::PermissionsChecker.new(
|
26
23
|
@resource,
|
27
|
-
'
|
24
|
+
'browseEnabled',
|
28
25
|
@rendering_id,
|
29
|
-
|
30
|
-
get_collection_list_permission_info(forest_user, request)
|
26
|
+
user_id: forest_user['id'],
|
27
|
+
collection_list_parameters: get_collection_list_permission_info(forest_user, request)
|
31
28
|
)
|
32
29
|
return head :forbidden unless checker.is_authorized?
|
33
30
|
end
|
@@ -59,10 +56,10 @@ module ForestLiana
|
|
59
56
|
begin
|
60
57
|
checker = ForestLiana::PermissionsChecker.new(
|
61
58
|
@resource,
|
62
|
-
'
|
59
|
+
'browseEnabled',
|
63
60
|
@rendering_id,
|
64
|
-
|
65
|
-
get_collection_list_permission_info(forest_user, request)
|
61
|
+
user_id: forest_user['id'],
|
62
|
+
collection_list_parameters: get_collection_list_permission_info(forest_user, request)
|
66
63
|
)
|
67
64
|
return head :forbidden unless checker.is_authorized?
|
68
65
|
|
@@ -89,7 +86,7 @@ module ForestLiana
|
|
89
86
|
|
90
87
|
def show
|
91
88
|
begin
|
92
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, '
|
89
|
+
checker = ForestLiana::PermissionsChecker.new(@resource, 'readEnabled', @rendering_id, user_id: forest_user['id'])
|
93
90
|
return head :forbidden unless checker.is_authorized?
|
94
91
|
|
95
92
|
getter = ForestLiana::ResourceGetter.new(@resource, params)
|
@@ -104,7 +101,7 @@ module ForestLiana
|
|
104
101
|
|
105
102
|
def create
|
106
103
|
begin
|
107
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, '
|
104
|
+
checker = ForestLiana::PermissionsChecker.new(@resource, 'addEnabled', @rendering_id, user_id: forest_user['id'])
|
108
105
|
return head :forbidden unless checker.is_authorized?
|
109
106
|
|
110
107
|
creator = ForestLiana::ResourceCreator.new(@resource, params)
|
@@ -127,7 +124,7 @@ module ForestLiana
|
|
127
124
|
|
128
125
|
def update
|
129
126
|
begin
|
130
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, '
|
127
|
+
checker = ForestLiana::PermissionsChecker.new(@resource, 'editEnabled', @rendering_id, user_id: forest_user['id'])
|
131
128
|
return head :forbidden unless checker.is_authorized?
|
132
129
|
|
133
130
|
updater = ForestLiana::ResourceUpdater.new(@resource, params)
|
@@ -149,7 +146,7 @@ module ForestLiana
|
|
149
146
|
end
|
150
147
|
|
151
148
|
def destroy
|
152
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, '
|
149
|
+
checker = ForestLiana::PermissionsChecker.new(@resource, 'deleteEnabled', @rendering_id, user_id: forest_user['id'])
|
153
150
|
return head :forbidden unless checker.is_authorized?
|
154
151
|
|
155
152
|
@resource.destroy(params[:id]) if @resource.exists?(params[:id])
|
@@ -161,7 +158,7 @@ module ForestLiana
|
|
161
158
|
end
|
162
159
|
|
163
160
|
def destroy_bulk
|
164
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, '
|
161
|
+
checker = ForestLiana::PermissionsChecker.new(@resource, 'deleteEnabled', @rendering_id, user_id: forest_user['id'])
|
165
162
|
return head :forbidden unless checker.is_authorized?
|
166
163
|
|
167
164
|
ids = ForestLiana::ResourcesGetter.get_ids_from_request(params)
|
@@ -245,8 +242,8 @@ module ForestLiana
|
|
245
242
|
@collection ||= ForestLiana.apimap.find { |collection| collection.name.to_s == collection_name }
|
246
243
|
end
|
247
244
|
|
248
|
-
# NOTICE: Return a formatted object containing the request condition filters and
|
249
|
-
# the user id used by the scope validator class to validate if scope is
|
245
|
+
# NOTICE: Return a formatted object containing the request condition filters and
|
246
|
+
# the user id used by the scope validator class to validate if scope is
|
250
247
|
# in request
|
251
248
|
def get_collection_list_permission_info(user, collection_list_request)
|
252
249
|
{
|
@@ -19,14 +19,15 @@ module ForestLiana
|
|
19
19
|
|
20
20
|
def check_permission_for_smart_route
|
21
21
|
begin
|
22
|
-
|
22
|
+
|
23
23
|
smart_action_request = get_smart_action_request
|
24
24
|
if !smart_action_request.nil? && smart_action_request.has_key?(:smart_action_id)
|
25
25
|
checker = ForestLiana::PermissionsChecker.new(
|
26
26
|
find_resource(smart_action_request[:collection_name]),
|
27
27
|
'actions',
|
28
28
|
@rendering_id,
|
29
|
-
|
29
|
+
user_id: forest_user['id'],
|
30
|
+
smart_action_request_info: get_smart_action_request_info
|
30
31
|
)
|
31
32
|
return head :forbidden unless checker.is_authorized?
|
32
33
|
else
|
@@ -54,10 +55,14 @@ module ForestLiana
|
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
57
|
-
|
58
|
+
# smart action permissions are retrieved from the action's endpoint and http_method
|
59
|
+
def get_smart_action_request_info
|
60
|
+
endpoint = request.fullpath
|
61
|
+
# Trim starting '/'
|
62
|
+
endpoint[0] = '' if endpoint[0] == '/'
|
58
63
|
{
|
59
|
-
|
60
|
-
|
64
|
+
endpoint: endpoint,
|
65
|
+
http_method: request.request_method
|
61
66
|
}
|
62
67
|
end
|
63
68
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module ForestLiana
|
4
|
+
module IsSameDataStructureHelper
|
5
|
+
class Analyser
|
6
|
+
def initialize(object, other, deep = 0)
|
7
|
+
@object = object
|
8
|
+
@other = other
|
9
|
+
@deep = deep
|
10
|
+
end
|
11
|
+
|
12
|
+
def are_objects(object, other)
|
13
|
+
object && other && object.is_a?(Hash) && other.is_a?(Hash)
|
14
|
+
end
|
15
|
+
|
16
|
+
def check_keys(object, other, step = 0)
|
17
|
+
unless are_objects(object, other)
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
|
21
|
+
object_keys = object.keys
|
22
|
+
other_keys = other.keys
|
23
|
+
|
24
|
+
if object_keys.length != other_keys.length
|
25
|
+
return false
|
26
|
+
end
|
27
|
+
|
28
|
+
object_keys_set = object_keys.to_set
|
29
|
+
other_keys.each { |key|
|
30
|
+
if !object_keys_set.member?(key) || (step + 1 <= @deep && !check_keys(object[key], other[key], step + 1))
|
31
|
+
return false
|
32
|
+
end
|
33
|
+
}
|
34
|
+
|
35
|
+
return true
|
36
|
+
end
|
37
|
+
|
38
|
+
def perform
|
39
|
+
check_keys(@object, @other)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module ForestLiana
|
4
|
+
module WidgetsHelper
|
5
|
+
|
6
|
+
@widget_edit_list = [
|
7
|
+
'address editor',
|
8
|
+
'belongsto typeahead',
|
9
|
+
'belongsto dropdown',
|
10
|
+
'boolean editor',
|
11
|
+
'checkboxes',
|
12
|
+
'color editor',
|
13
|
+
'date editor',
|
14
|
+
'dropdown',
|
15
|
+
'embedded document editor',
|
16
|
+
'file picker',
|
17
|
+
'json code editor',
|
18
|
+
'input array',
|
19
|
+
'multiple select',
|
20
|
+
'number input',
|
21
|
+
'point editor',
|
22
|
+
'price editor',
|
23
|
+
'radio button',
|
24
|
+
'rich text',
|
25
|
+
'text area editor',
|
26
|
+
'text editor',
|
27
|
+
'time input',
|
28
|
+
]
|
29
|
+
|
30
|
+
@v1_to_v2_edit_widgets_mapping = {
|
31
|
+
address: 'address editor',
|
32
|
+
'belongsto select': 'belongsto dropdown',
|
33
|
+
'color picker': 'color editor',
|
34
|
+
'date picker': 'date editor',
|
35
|
+
price: 'price editor',
|
36
|
+
'JSON editor': 'json code editor',
|
37
|
+
'rich text editor': 'rich text',
|
38
|
+
'text area': 'text area editor',
|
39
|
+
'text input': 'text editor',
|
40
|
+
}
|
41
|
+
|
42
|
+
def self.set_field_widget(field)
|
43
|
+
|
44
|
+
if field[:widget]
|
45
|
+
if @v1_to_v2_edit_widgets_mapping[field[:widget].to_sym]
|
46
|
+
field[:widgetEdit] = {name: @v1_to_v2_edit_widgets_mapping[field[:widget].to_sym], parameters: {}}
|
47
|
+
elsif @widget_edit_list.include?(field[:widget])
|
48
|
+
field[:widgetEdit] = {name: field[:widget], parameters: {}}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
if !field.key?(:widgetEdit)
|
53
|
+
field[:widgetEdit] = nil
|
54
|
+
end
|
55
|
+
|
56
|
+
field.delete(:widget)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -5,7 +5,7 @@ class ForestLiana::Model::Action
|
|
5
5
|
extend ActiveModel::Naming
|
6
6
|
|
7
7
|
attr_accessor :id, :name, :base_url, :endpoint, :http_method, :fields, :redirect,
|
8
|
-
:type, :download
|
8
|
+
:type, :download, :hooks
|
9
9
|
|
10
10
|
def initialize(attributes = {})
|
11
11
|
if attributes.key?(:global)
|
@@ -66,6 +66,7 @@ class ForestLiana::Model::Action
|
|
66
66
|
@base_url ||= nil
|
67
67
|
@type ||= "bulk"
|
68
68
|
@download ||= false
|
69
|
+
@hooks = !@hooks.nil? ? @hooks.symbolize_keys : nil
|
69
70
|
end
|
70
71
|
|
71
72
|
def persisted?
|
@@ -1,100 +1,162 @@
|
|
1
1
|
module ForestLiana
|
2
2
|
class PermissionsChecker
|
3
|
-
@@
|
3
|
+
@@permissions_cached = Hash.new
|
4
|
+
@@scopes_cached = Hash.new
|
5
|
+
@@roles_acl_activated = false
|
6
|
+
# TODO: handle cache scopes per rendering
|
4
7
|
@@expiration_in_seconds = (ENV['FOREST_PERMISSIONS_EXPIRATION_IN_SECONDS'] || 3600).to_i
|
5
8
|
|
6
|
-
def initialize(resource, permission_name, rendering_id,
|
9
|
+
def initialize(resource, permission_name, rendering_id, user_id:, smart_action_request_info: nil, collection_list_parameters: nil)
|
10
|
+
@user_id = user_id
|
7
11
|
@collection_name = ForestLiana.name_for(resource)
|
8
12
|
@permission_name = permission_name
|
9
13
|
@rendering_id = rendering_id
|
10
|
-
@
|
14
|
+
@smart_action_request_info = smart_action_request_info
|
11
15
|
@collection_list_parameters = collection_list_parameters
|
12
16
|
end
|
13
17
|
|
14
18
|
def is_authorized?
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
private
|
19
|
+
# User is still authorized if he already was and the permission has not expire
|
20
|
+
# if !have_permissions_expired && is_allowed
|
21
|
+
return true unless have_permissions_expired? || !is_allowed
|
19
22
|
|
20
|
-
|
21
|
-
|
22
|
-
@@permissions_per_rendering[@rendering_id] &&
|
23
|
-
@@permissions_per_rendering[@rendering_id]['data']
|
23
|
+
fetch_permissions
|
24
|
+
is_allowed
|
24
25
|
end
|
25
26
|
|
26
|
-
|
27
|
-
@@permissions_per_rendering &&
|
28
|
-
@@permissions_per_rendering[@rendering_id] &&
|
29
|
-
@@permissions_per_rendering[@rendering_id]['last_retrieve']
|
30
|
-
end
|
27
|
+
private
|
31
28
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
29
|
+
def fetch_permissions
|
30
|
+
permissions = ForestLiana::PermissionsGetter::get_permissions_for_rendering(@rendering_id)
|
31
|
+
@@roles_acl_activated = permissions['meta']['rolesACLActivated']
|
32
|
+
permissions['last_fetch'] = Time.now
|
33
|
+
if @@roles_acl_activated
|
34
|
+
@@permissions_cached = permissions
|
35
|
+
else
|
36
|
+
permissions['data'] = ForestLiana::PermissionsFormatter.convert_to_new_format(permissions['data'], @rendering_id)
|
37
|
+
@@permissions_cached[@rendering_id] = permissions
|
39
38
|
end
|
40
|
-
|
41
|
-
@user_id = @smart_action_parameters[:user_id]
|
42
|
-
@action_id = @smart_action_parameters[:action_id]
|
43
|
-
@smart_action_permissions = smart_actions_permissions[@action_id]
|
44
|
-
@allowed = @smart_action_permissions['allowed']
|
45
|
-
@users = @smart_action_permissions['users']
|
46
|
-
|
47
|
-
return @allowed && (@users.nil?|| @users.include?(@user_id.to_i));
|
39
|
+
add_scopes_to_cache(permissions)
|
48
40
|
end
|
49
41
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
42
|
+
def add_scopes_to_cache(permissions)
|
43
|
+
permissions['data']['renderings'].keys.each { |rendering_id|
|
44
|
+
@@scopes_cached[rendering_id] = permissions['data']['renderings'][rendering_id]
|
45
|
+
@@scopes_cached[rendering_id]['last_fetch'] = Time.now
|
46
|
+
} if permissions['data']['renderings']
|
55
47
|
end
|
56
48
|
|
57
|
-
def is_allowed
|
58
|
-
permissions =
|
49
|
+
def is_allowed
|
50
|
+
permissions = get_permissions_content
|
51
|
+
|
59
52
|
if permissions && permissions[@collection_name] &&
|
60
53
|
permissions[@collection_name]['collection']
|
61
54
|
if @permission_name === 'actions'
|
62
55
|
return smart_action_allowed?(permissions[@collection_name]['actions'])
|
63
|
-
# NOTICE: Permissions[@collection_name]['scope'] will either contains conditions filter and
|
64
|
-
# dynamic user values definition, or null for collection that does not use scopes
|
65
|
-
elsif @permission_name === 'list' and permissions[@collection_name]['scope']
|
66
|
-
return collection_list_allowed?(permissions[@collection_name]['scope'])
|
67
56
|
else
|
68
|
-
|
57
|
+
if @permission_name === 'browseEnabled'
|
58
|
+
refresh_scope_cache if scope_cache_expired?
|
59
|
+
scope_permissions = get_scope_in_permissions
|
60
|
+
if scope_permissions
|
61
|
+
# NOTICE: current_scope will either contains conditions filter and
|
62
|
+
# dynamic user values definition, or null for collection that does not use scopes
|
63
|
+
return false unless are_scopes_valid?(scope_permissions)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
return is_user_allowed(permissions[@collection_name]['collection'][@permission_name])
|
69
67
|
end
|
70
68
|
else
|
71
69
|
false
|
72
70
|
end
|
73
71
|
end
|
74
72
|
|
75
|
-
def
|
76
|
-
@@
|
77
|
-
|
78
|
-
@@
|
79
|
-
|
73
|
+
def get_scope_in_permissions
|
74
|
+
@@scopes_cached[@rendering_id] &&
|
75
|
+
@@scopes_cached[@rendering_id][@collection_name] &&
|
76
|
+
@@scopes_cached[@rendering_id][@collection_name]['scope']
|
77
|
+
end
|
78
|
+
|
79
|
+
def scope_cache_expired?
|
80
|
+
return true unless @@scopes_cached[@rendering_id] && @@scopes_cached[@rendering_id]['last_fetch']
|
81
|
+
|
82
|
+
elapsed_seconds = date_difference_in_seconds(Time.now, @@scopes_cached[@rendering_id]['last_fetch'])
|
83
|
+
elapsed_seconds >= @@expiration_in_seconds
|
84
|
+
end
|
85
|
+
|
86
|
+
# This will happen only on rolesACLActivated (as scope cache will always be up to date on disabled)
|
87
|
+
def refresh_scope_cache
|
88
|
+
permissions = ForestLiana::PermissionsGetter::get_permissions_for_rendering(@rendering_id, rendering_specific_only: true)
|
89
|
+
add_scopes_to_cache(permissions)
|
90
|
+
end
|
91
|
+
|
92
|
+
# When acl disabled permissions are stored and retrieved by rendering
|
93
|
+
def get_permissions
|
94
|
+
@@roles_acl_activated ? @@permissions_cached : @@permissions_cached[@rendering_id]
|
95
|
+
end
|
96
|
+
|
97
|
+
def get_permissions_content
|
98
|
+
permissions = get_permissions
|
99
|
+
permissions && permissions['data'] && permissions['data']['collections']
|
100
|
+
end
|
101
|
+
|
102
|
+
def get_last_fetch
|
103
|
+
permissions = get_permissions
|
104
|
+
permissions && permissions['last_fetch']
|
105
|
+
end
|
106
|
+
|
107
|
+
def get_smart_action_permissions(smart_actions_permissions)
|
108
|
+
endpoint = @smart_action_request_info[:endpoint]
|
109
|
+
http_method = @smart_action_request_info[:http_method]
|
110
|
+
|
111
|
+
return nil unless endpoint && http_method
|
112
|
+
|
113
|
+
schema_smart_action = ForestLiana::Utils::BetaSchemaUtils.find_action_from_endpoint(@collection_name, endpoint, http_method)
|
114
|
+
|
115
|
+
schema_smart_action &&
|
116
|
+
schema_smart_action.name &&
|
117
|
+
smart_actions_permissions &&
|
118
|
+
smart_actions_permissions[schema_smart_action.name]
|
119
|
+
end
|
120
|
+
|
121
|
+
def is_user_allowed(permission_value)
|
122
|
+
return false if permission_value.nil?
|
123
|
+
return permission_value if permission_value.in? [true, false]
|
124
|
+
permission_value.include?(@user_id.to_i)
|
125
|
+
end
|
126
|
+
|
127
|
+
def smart_action_allowed?(smart_actions_permissions)
|
128
|
+
smart_action_permissions = get_smart_action_permissions(smart_actions_permissions)
|
129
|
+
|
130
|
+
return false unless smart_action_permissions
|
131
|
+
|
132
|
+
is_user_allowed(smart_action_permissions['triggerEnabled'])
|
133
|
+
end
|
134
|
+
|
135
|
+
def are_scopes_valid?(scope_permissions)
|
136
|
+
return ForestLiana::ScopeValidator.new(
|
137
|
+
scope_permissions['filter'],
|
138
|
+
scope_permissions['dynamicScopesValues']['users']
|
139
|
+
).is_scope_in_request?(@collection_list_parameters)
|
80
140
|
end
|
81
141
|
|
82
142
|
def date_difference_in_seconds(date1, date2)
|
83
143
|
(date1 - date2).to_i
|
84
144
|
end
|
85
145
|
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
return true if last_retrieve.nil?
|
146
|
+
def have_permissions_expired?
|
147
|
+
last_fetch = get_last_fetch
|
148
|
+
return true unless last_fetch
|
90
149
|
|
91
|
-
elapsed_seconds = date_difference_in_seconds(Time.now,
|
150
|
+
elapsed_seconds = date_difference_in_seconds(Time.now, last_fetch)
|
92
151
|
elapsed_seconds >= @@expiration_in_seconds
|
93
152
|
end
|
94
153
|
|
95
|
-
|
96
|
-
|
97
|
-
|
154
|
+
# Used only for testing purpose
|
155
|
+
def self.empty_cache
|
156
|
+
@@permissions_cached = Hash.new
|
157
|
+
@@scopes_cached = Hash.new
|
158
|
+
@@roles_acl_activated = false
|
159
|
+
@@expiration_in_seconds = (ENV['FOREST_PERMISSIONS_EXPIRATION_IN_SECONDS'] || 3600).to_i
|
98
160
|
end
|
99
161
|
end
|
100
162
|
end
|