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.
- checksums.yaml +4 -4
- data/app/controllers/forest_liana/actions_controller.rb +5 -3
- data/app/controllers/forest_liana/application_controller.rb +15 -0
- data/app/controllers/forest_liana/resources_controller.rb +31 -57
- data/app/controllers/forest_liana/smart_actions_controller.rb +44 -58
- data/app/controllers/forest_liana/stats_controller.rb +14 -58
- data/app/services/forest_liana/ability/exceptions/access_denied.rb +16 -0
- data/app/services/forest_liana/ability/exceptions/action_condition_error.rb +16 -0
- data/app/services/forest_liana/ability/exceptions/require_approval.rb +18 -0
- data/app/services/forest_liana/ability/exceptions/trigger_forbidden.rb +16 -0
- data/app/services/forest_liana/ability/fetch.rb +23 -0
- data/app/services/forest_liana/ability/permission/request_permission.rb +19 -0
- data/app/services/forest_liana/ability/permission/smart_action_checker.rb +71 -0
- data/app/services/forest_liana/ability/permission.rb +148 -0
- data/app/services/forest_liana/ability.rb +24 -0
- data/app/services/forest_liana/filters_parser.rb +7 -7
- data/app/services/forest_liana/leaderboard_stat_getter.rb +7 -7
- data/app/services/forest_liana/line_stat_getter.rb +8 -8
- data/app/services/forest_liana/pie_stat_getter.rb +17 -17
- data/app/services/forest_liana/stat_getter.rb +1 -2
- data/app/services/forest_liana/value_stat_getter.rb +7 -7
- data/lib/forest_liana/bootstrapper.rb +1 -1
- data/lib/forest_liana/version.rb +1 -1
- data/spec/dummy/lib/forest_liana/collections/island.rb +1 -1
- data/spec/requests/actions_controller_spec.rb +3 -4
- data/spec/requests/count_spec.rb +5 -9
- data/spec/requests/resources_spec.rb +55 -11
- data/spec/requests/stats_spec.rb +103 -42
- data/spec/services/forest_liana/ability/ability_spec.rb +48 -0
- data/spec/services/forest_liana/ability/permission/smart_action_checker_spec.rb +357 -0
- data/spec/services/forest_liana/ability/permission_spec.rb +332 -0
- data/spec/services/forest_liana/filters_parser_spec.rb +0 -12
- data/spec/services/forest_liana/line_stat_getter_spec.rb +9 -9
- data/spec/services/forest_liana/pie_stat_getter_spec.rb +7 -7
- data/spec/services/forest_liana/value_stat_getter_spec.rb +11 -11
- data/spec/spec_helper.rb +1 -0
- metadata +33 -17
- data/app/services/forest_liana/permissions_checker.rb +0 -223
- data/app/services/forest_liana/permissions_formatter.rb +0 -52
- data/app/services/forest_liana/permissions_getter.rb +0 -59
- data/spec/services/forest_liana/permissions_checker_acl_disabled_spec.rb +0 -713
- data/spec/services/forest_liana/permissions_checker_acl_enabled_spec.rb +0 -845
- data/spec/services/forest_liana/permissions_checker_live_queries_spec.rb +0 -175
- data/spec/services/forest_liana/permissions_formatter_spec.rb +0 -222
- data/spec/services/forest_liana/permissions_getter_spec.rb +0 -83
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8c3bc9feb8975c2d4bb725c5badda68b4d880fcc3a2553cc2d1d6164f5e56366
|
4
|
+
data.tar.gz: b1f6e70a0723450674b53944f933036fea21b4a9b6cceab806cf32cd7654896a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 42a2ae2c6800ea8cf501ee3896554852cd677003d2aea5353fbc2d74d5dee34ee55d02079f8a9a31949af19d7a6ecc8c97e8be3a15a9844aa2ae11ff2fb75e73
|
7
|
+
data.tar.gz: 2a97e185ccde89910027740ea833a8e3373f4cb2466a16c2023554534be4ddc3c2419d40015be0edbecb6283a304d4ef4b80472fcea98b99649a122b28fb9c2e
|
@@ -2,12 +2,14 @@ module ForestLiana
|
|
2
2
|
class ActionsController < ApplicationController
|
3
3
|
|
4
4
|
def get_smart_action_hook_request
|
5
|
-
|
5
|
+
if params[:data] && params[:data][:attributes] && params[:data][:attributes][:collection_name]
|
6
6
|
params[:data][:attributes]
|
7
|
-
|
7
|
+
else
|
8
|
+
error = 'parameters data attributes missing'
|
8
9
|
FOREST_REPORTER.report error
|
9
10
|
FOREST_LOGGER.error "Smart Action hook request error: #{error}"
|
10
|
-
|
11
|
+
|
12
|
+
raise ForestLiana::Errors::HTTP422Error.new("Error in smart action load hook: cannot retrieve action from collection")
|
11
13
|
end
|
12
14
|
end
|
13
15
|
|
@@ -3,6 +3,9 @@ require 'csv'
|
|
3
3
|
|
4
4
|
module ForestLiana
|
5
5
|
class ApplicationController < ForestLiana::BaseController
|
6
|
+
rescue_from ForestLiana::Ability::Exceptions::AccessDenied, with: :render_error
|
7
|
+
rescue_from ForestLiana::Errors::HTTP422Error, with: :render_error
|
8
|
+
|
6
9
|
def self.papertrail?
|
7
10
|
Object.const_get('PaperTrail::Version').is_a?(Class) rescue false
|
8
11
|
end
|
@@ -96,6 +99,18 @@ module ForestLiana
|
|
96
99
|
|
97
100
|
private
|
98
101
|
|
102
|
+
def render_error(exception)
|
103
|
+
errors = {
|
104
|
+
status: exception.error_code,
|
105
|
+
detail: exception.message,
|
106
|
+
}
|
107
|
+
|
108
|
+
errors['name'] = exception.name if exception.try(:name)
|
109
|
+
errors['data'] = exception.data if exception.try(:data)
|
110
|
+
|
111
|
+
render json: { errors: [errors] }, status: exception.status
|
112
|
+
end
|
113
|
+
|
99
114
|
def force_utf8_encoding(json)
|
100
115
|
if json['data'].class == Array
|
101
116
|
# NOTICE: Collection of records case
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module ForestLiana
|
2
2
|
class ResourcesController < ForestLiana::ApplicationController
|
3
|
+
include ForestLiana::Ability
|
3
4
|
begin
|
4
5
|
prepend ResourcesExtensions
|
5
6
|
rescue NameError
|
@@ -14,24 +15,11 @@ module ForestLiana
|
|
14
15
|
end
|
15
16
|
|
16
17
|
def index
|
18
|
+
action = request.format == 'csv' ? 'export' : 'browse'
|
19
|
+
forest_authorize!(action, forest_user, @resource)
|
17
20
|
begin
|
18
|
-
if request.format == 'csv'
|
19
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, 'exportEnabled', @rendering_id, user: forest_user)
|
20
|
-
return head :forbidden unless checker.is_authorized?
|
21
|
-
else
|
22
|
-
checker = ForestLiana::PermissionsChecker.new(
|
23
|
-
@resource,
|
24
|
-
'browseEnabled',
|
25
|
-
@rendering_id,
|
26
|
-
user: forest_user,
|
27
|
-
collection_list_parameters: get_collection_list_permission_info(forest_user, request)
|
28
|
-
)
|
29
|
-
return head :forbidden unless checker.is_authorized?
|
30
|
-
end
|
31
|
-
|
32
21
|
getter = ForestLiana::ResourcesGetter.new(@resource, params, forest_user)
|
33
22
|
getter.perform
|
34
|
-
|
35
23
|
respond_to do |format|
|
36
24
|
format.json { render_jsonapi(getter) }
|
37
25
|
format.csv { render_csv(getter, @resource) }
|
@@ -55,16 +43,8 @@ module ForestLiana
|
|
55
43
|
|
56
44
|
def count
|
57
45
|
find_resource
|
46
|
+
forest_authorize!('browse', forest_user, @resource)
|
58
47
|
begin
|
59
|
-
checker = ForestLiana::PermissionsChecker.new(
|
60
|
-
@resource,
|
61
|
-
'browseEnabled',
|
62
|
-
@rendering_id,
|
63
|
-
user: forest_user,
|
64
|
-
collection_list_parameters: get_collection_list_permission_info(forest_user, request)
|
65
|
-
)
|
66
|
-
return head :forbidden unless checker.is_authorized?
|
67
|
-
|
68
48
|
getter = ForestLiana::ResourcesGetter.new(@resource, params, forest_user)
|
69
49
|
getter.count
|
70
50
|
|
@@ -88,10 +68,8 @@ module ForestLiana
|
|
88
68
|
end
|
89
69
|
|
90
70
|
def show
|
71
|
+
forest_authorize!('read', forest_user, @resource)
|
91
72
|
begin
|
92
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, 'readEnabled', @rendering_id, user: forest_user)
|
93
|
-
return head :forbidden unless checker.is_authorized?
|
94
|
-
|
95
73
|
getter = ForestLiana::ResourceGetter.new(@resource, params, forest_user)
|
96
74
|
getter.perform
|
97
75
|
|
@@ -106,10 +84,8 @@ module ForestLiana
|
|
106
84
|
end
|
107
85
|
|
108
86
|
def create
|
87
|
+
forest_authorize!('add', forest_user, @resource)
|
109
88
|
begin
|
110
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, 'addEnabled', @rendering_id, user: forest_user)
|
111
|
-
return head :forbidden unless checker.is_authorized?
|
112
|
-
|
113
89
|
creator = ForestLiana::ResourceCreator.new(@resource, params)
|
114
90
|
creator.perform
|
115
91
|
|
@@ -130,10 +106,8 @@ module ForestLiana
|
|
130
106
|
end
|
131
107
|
|
132
108
|
def update
|
109
|
+
forest_authorize!('edit', forest_user, @resource)
|
133
110
|
begin
|
134
|
-
checker = ForestLiana::PermissionsChecker.new(@resource, 'editEnabled', @rendering_id, user: forest_user)
|
135
|
-
return head :forbidden unless checker.is_authorized?
|
136
|
-
|
137
111
|
updater = ForestLiana::ResourceUpdater.new(@resource, params, forest_user)
|
138
112
|
updater.perform
|
139
113
|
|
@@ -154,37 +128,37 @@ module ForestLiana
|
|
154
128
|
end
|
155
129
|
|
156
130
|
def destroy
|
157
|
-
|
158
|
-
|
131
|
+
forest_authorize!('delete', forest_user, @resource)
|
132
|
+
begin
|
133
|
+
collection_name = ForestLiana.name_for(@resource)
|
134
|
+
scoped_records = ForestLiana::ScopeManager.apply_scopes_on_records(@resource, forest_user, collection_name, params[:timezone])
|
159
135
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
unless scoped_records.exists?(params[:id])
|
164
|
-
return render serializer: nil, json: { status: 404 }, status: :not_found
|
165
|
-
end
|
136
|
+
unless scoped_records.exists?(params[:id])
|
137
|
+
return render serializer: nil, json: { status: 404 }, status: :not_found
|
138
|
+
end
|
166
139
|
|
167
|
-
|
140
|
+
scoped_records.destroy(params[:id])
|
168
141
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
142
|
+
head :no_content
|
143
|
+
rescue => error
|
144
|
+
FOREST_REPORTER.report error
|
145
|
+
FOREST_LOGGER.error "Record Destroy error: #{error}\n#{format_stacktrace(error)}"
|
146
|
+
internal_server_error
|
147
|
+
end
|
174
148
|
end
|
175
149
|
|
176
150
|
def destroy_bulk
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
@resource.destroy(ids) if ids&.any?
|
151
|
+
forest_authorize!('delete', forest_user, @resource)
|
152
|
+
begin
|
153
|
+
ids = ForestLiana::ResourcesGetter.get_ids_from_request(params, forest_user)
|
154
|
+
@resource.destroy(ids) if ids&.any?
|
182
155
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
156
|
+
head :no_content
|
157
|
+
rescue => error
|
158
|
+
FOREST_REPORTER.report error
|
159
|
+
FOREST_LOGGER.error "Records Destroy error: #{error}\n#{format_stacktrace(error)}"
|
160
|
+
internal_server_error
|
161
|
+
end
|
188
162
|
end
|
189
163
|
|
190
164
|
private
|
@@ -1,5 +1,9 @@
|
|
1
1
|
module ForestLiana
|
2
2
|
class SmartActionsController < ForestLiana::ApplicationController
|
3
|
+
rescue_from ForestLiana::Ability::Exceptions::TriggerForbidden, with: :render_error
|
4
|
+
rescue_from ForestLiana::Ability::Exceptions::RequireApproval, with: :render_error
|
5
|
+
rescue_from ForestLiana::Ability::Exceptions::ActionConditionError, with: :render_error
|
6
|
+
include ForestLiana::Ability
|
3
7
|
if Rails::VERSION::MAJOR < 4
|
4
8
|
before_filter :smart_action_pre_perform_checks
|
5
9
|
else
|
@@ -8,9 +12,17 @@ module ForestLiana
|
|
8
12
|
|
9
13
|
private
|
10
14
|
|
15
|
+
def smart_action_pre_perform_checks
|
16
|
+
get_smart_action_request
|
17
|
+
find_resource
|
18
|
+
check_permission_for_smart_route
|
19
|
+
ensure_record_ids_in_scope
|
20
|
+
end
|
21
|
+
|
11
22
|
def get_smart_action_request
|
12
23
|
begin
|
13
24
|
params[:data][:attributes]
|
25
|
+
@parameters = ForestLiana::Ability::Permission::RequestPermission::decodeSignedApprovalRequest(params.permit!)
|
14
26
|
rescue => error
|
15
27
|
FOREST_REPORTER.report error
|
16
28
|
FOREST_LOGGER.error "Smart Action execution error: #{error}"
|
@@ -18,29 +30,52 @@ module ForestLiana
|
|
18
30
|
end
|
19
31
|
end
|
20
32
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
33
|
+
def find_resource
|
34
|
+
begin
|
35
|
+
@resource = SchemaUtils.find_model_from_collection_name(@parameters[:data][:attributes][:collection_name])
|
36
|
+
if @resource.nil? || !SchemaUtils.model_included?(@resource) ||
|
37
|
+
!@resource.ancestors.include?(ActiveRecord::Base)
|
38
|
+
render serializer: nil, json: { status: 404 }, status: :not_found
|
39
|
+
end
|
40
|
+
@resource
|
41
|
+
rescue => error
|
42
|
+
FOREST_REPORTER.report error
|
43
|
+
FOREST_LOGGER.error "Find Collection error: #{error}\n#{format_stacktrace(error)}"
|
44
|
+
render serializer: nil, json: { status: 404 }, status: :not_found
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def check_permission_for_smart_route
|
49
|
+
smart_action_request = @parameters[:data][:attributes]
|
50
|
+
if !smart_action_request.nil? && smart_action_request.has_key?(:smart_action_id)
|
51
|
+
forest_authorize!(
|
52
|
+
'action',
|
53
|
+
forest_user,
|
54
|
+
@resource,
|
55
|
+
{parameters: params, endpoint: request.fullpath.split('?').first, http_method: request.request_method}
|
56
|
+
)
|
57
|
+
else
|
58
|
+
FOREST_LOGGER.error 'Smart action execution error: Unable to retrieve the smart action id.'
|
59
|
+
render serializer: nil, json: { status: 400 }, status: :bad_request
|
60
|
+
end
|
24
61
|
end
|
25
62
|
|
26
63
|
def ensure_record_ids_in_scope
|
27
64
|
begin
|
28
|
-
attributes =
|
65
|
+
attributes = @parameters[:data][:attributes]
|
29
66
|
|
30
67
|
# if performing a `selectAll` let the `get_ids_from_request` handle the scopes
|
31
68
|
return if attributes[:all_records]
|
32
69
|
|
33
|
-
resource = find_resource(attributes[:collection_name])
|
34
|
-
|
35
70
|
# user is using the composite_primary_keys gem
|
36
|
-
if resource.primary_key.kind_of?(Array)
|
71
|
+
if @resource.primary_key.kind_of?(Array)
|
37
72
|
# TODO: handle primary keys
|
38
73
|
return
|
39
74
|
end
|
40
75
|
|
41
|
-
filter = JSON.generate({ 'field' => resource.primary_key, 'operator' => 'in', 'value' => attributes[:ids] })
|
76
|
+
filter = JSON.generate({ 'field' => @resource.primary_key, 'operator' => 'in', 'value' => attributes[:ids] })
|
42
77
|
|
43
|
-
resources_getter = ForestLiana::ResourcesGetter.new(resource, { :filters => filter, :timezone => attributes[:timezone] }, forest_user)
|
78
|
+
resources_getter = ForestLiana::ResourcesGetter.new(@resource, { :filters => filter, :timezone => attributes[:timezone] }, forest_user)
|
44
79
|
|
45
80
|
# resources getter will return records inside the scope. if the length differs then ids are out of scope
|
46
81
|
return if resources_getter.count == attributes[:ids].length
|
@@ -53,54 +88,5 @@ module ForestLiana
|
|
53
88
|
render serializer: nil, json: { error: 'Smart Action: failed to evaluate permissions' }, status: :internal_server_error
|
54
89
|
end
|
55
90
|
end
|
56
|
-
|
57
|
-
def check_permission_for_smart_route
|
58
|
-
begin
|
59
|
-
|
60
|
-
smart_action_request = get_smart_action_request
|
61
|
-
if !smart_action_request.nil? && smart_action_request.has_key?(:smart_action_id)
|
62
|
-
checker = ForestLiana::PermissionsChecker.new(
|
63
|
-
find_resource(smart_action_request[:collection_name]),
|
64
|
-
'actions',
|
65
|
-
@rendering_id,
|
66
|
-
user: forest_user,
|
67
|
-
smart_action_request_info: get_smart_action_request_info
|
68
|
-
)
|
69
|
-
return head :forbidden unless checker.is_authorized?
|
70
|
-
else
|
71
|
-
FOREST_LOGGER.error 'Smart action execution error: Unable to retrieve the smart action id.'
|
72
|
-
render serializer: nil, json: { status: 400 }, status: :bad_request
|
73
|
-
end
|
74
|
-
rescue => error
|
75
|
-
FOREST_REPORTER.report error
|
76
|
-
FOREST_LOGGER.error "Smart Action execution error: #{error}"
|
77
|
-
render serializer: nil, json: { status: 400 }, status: :bad_request
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def find_resource(collection_name)
|
82
|
-
begin
|
83
|
-
resource = SchemaUtils.find_model_from_collection_name(collection_name)
|
84
|
-
|
85
|
-
if resource.nil? || !SchemaUtils.model_included?(resource) ||
|
86
|
-
!resource.ancestors.include?(ActiveRecord::Base)
|
87
|
-
render serializer: nil, json: { status: 404 }, status: :not_found
|
88
|
-
end
|
89
|
-
resource
|
90
|
-
rescue => error
|
91
|
-
FOREST_REPORTER.report error
|
92
|
-
FOREST_LOGGER.error "Find Collection error: #{error}\n#{format_stacktrace(error)}"
|
93
|
-
render serializer: nil, json: { status: 404 }, status: :not_found
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
# smart action permissions are retrieved from the action's endpoint and http_method
|
98
|
-
def get_smart_action_request_info
|
99
|
-
{
|
100
|
-
# trim query params to get the endpoint
|
101
|
-
endpoint: request.fullpath.split('?').first,
|
102
|
-
http_method: request.request_method
|
103
|
-
}
|
104
|
-
end
|
105
91
|
end
|
106
92
|
end
|
@@ -1,22 +1,6 @@
|
|
1
1
|
module ForestLiana
|
2
2
|
class StatsController < ForestLiana::ApplicationController
|
3
|
-
|
4
|
-
before_filter only: [:get] do
|
5
|
-
find_resource()
|
6
|
-
check_permission('statWithParameters')
|
7
|
-
end
|
8
|
-
before_filter only: [:get_with_live_query] do
|
9
|
-
check_permission('liveQueries')
|
10
|
-
end
|
11
|
-
else
|
12
|
-
before_action only: [:get] do
|
13
|
-
find_resource()
|
14
|
-
check_permission('statWithParameters')
|
15
|
-
end
|
16
|
-
before_action only: [:get_with_live_query] do
|
17
|
-
check_permission('liveQueries')
|
18
|
-
end
|
19
|
-
end
|
3
|
+
include ForestLiana::Ability
|
20
4
|
|
21
5
|
CHART_TYPE_VALUE = 'Value'
|
22
6
|
CHART_TYPE_PIE = 'Pie'
|
@@ -24,7 +8,14 @@ module ForestLiana
|
|
24
8
|
CHART_TYPE_LEADERBOARD = 'Leaderboard'
|
25
9
|
CHART_TYPE_OBJECTIVE = 'Objective'
|
26
10
|
|
11
|
+
if Rails::VERSION::MAJOR < 4
|
12
|
+
before_filter :find_resource, only: :get
|
13
|
+
else
|
14
|
+
before_action :find_resource, only: :get
|
15
|
+
end
|
16
|
+
|
27
17
|
def get
|
18
|
+
forest_authorize!('chart', forest_user, nil, {parameters: params})
|
28
19
|
case params[:type]
|
29
20
|
when CHART_TYPE_VALUE
|
30
21
|
stat = ValueStatGetter.new(@resource, params, forest_user)
|
@@ -47,6 +38,7 @@ module ForestLiana
|
|
47
38
|
end
|
48
39
|
|
49
40
|
def get_with_live_query
|
41
|
+
forest_authorize!('chart', forest_user, nil, {parameters: params})
|
50
42
|
begin
|
51
43
|
stat = QueryStatGetter.new(params)
|
52
44
|
stat.perform
|
@@ -67,54 +59,18 @@ module ForestLiana
|
|
67
59
|
end
|
68
60
|
end
|
69
61
|
|
62
|
+
def params
|
63
|
+
super.permit!
|
64
|
+
end
|
65
|
+
|
70
66
|
private
|
71
67
|
|
72
68
|
def find_resource
|
73
|
-
@resource = SchemaUtils.find_model_from_collection_name(
|
74
|
-
params[:collection])
|
69
|
+
@resource = SchemaUtils.find_model_from_collection_name(params[:collection])
|
75
70
|
|
76
71
|
if @resource.nil? || !@resource.ancestors.include?(ActiveRecord::Base)
|
77
72
|
render json: {status: 404}, status: :not_found, serializer: nil
|
78
73
|
end
|
79
74
|
end
|
80
|
-
|
81
|
-
def get_live_query_request_info
|
82
|
-
params['query']
|
83
|
-
end
|
84
|
-
|
85
|
-
def get_stat_parameter_request_info
|
86
|
-
parameters = Rails::VERSION::MAJOR < 5 ? params.dup : params.permit(params.keys).to_h;
|
87
|
-
|
88
|
-
# Notice: Removes useless properties
|
89
|
-
parameters.delete('timezone');
|
90
|
-
parameters.delete('controller');
|
91
|
-
parameters.delete('action');
|
92
|
-
|
93
|
-
# NOTICE: Remove the field information from group_by_field => collection:id
|
94
|
-
if parameters['group_by_field']
|
95
|
-
parameters['group_by_field'] = parameters['group_by_field'].split(':').first
|
96
|
-
end
|
97
|
-
|
98
|
-
return parameters;
|
99
|
-
end
|
100
|
-
|
101
|
-
def check_permission(permission_name)
|
102
|
-
begin
|
103
|
-
query_request = permission_name == 'liveQueries' ? get_live_query_request_info : get_stat_parameter_request_info;
|
104
|
-
checker = ForestLiana::PermissionsChecker.new(
|
105
|
-
nil,
|
106
|
-
permission_name,
|
107
|
-
@rendering_id,
|
108
|
-
user: forest_user,
|
109
|
-
query_request_info: query_request
|
110
|
-
)
|
111
|
-
|
112
|
-
return head :forbidden unless checker.is_authorized?
|
113
|
-
rescue => error
|
114
|
-
FOREST_REPORTER.report error
|
115
|
-
FOREST_LOGGER.error "Stats execution error: #{error}"
|
116
|
-
render serializer: nil, json: { status: 400 }, status: :bad_request
|
117
|
-
end
|
118
|
-
end
|
119
75
|
end
|
120
76
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
module Ability
|
3
|
+
module Exceptions
|
4
|
+
class AccessDenied < ForestLiana::Errors::ExpectedError
|
5
|
+
def initialize
|
6
|
+
super(
|
7
|
+
403,
|
8
|
+
:forbidden,
|
9
|
+
'You don\'t have permission to access this resource',
|
10
|
+
'AccessDenied'
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
module Ability
|
3
|
+
module Exceptions
|
4
|
+
class ActionConditionError < ForestLiana::Errors::ExpectedError
|
5
|
+
def initialize
|
6
|
+
super(
|
7
|
+
409,
|
8
|
+
:conflict,
|
9
|
+
'The conditions to trigger this action cannot be verified. Please contact an administrator.',
|
10
|
+
'InvalidActionConditionError'
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
module Ability
|
3
|
+
module Exceptions
|
4
|
+
class RequireApproval < ForestLiana::Errors::ExpectedError
|
5
|
+
attr_reader :data
|
6
|
+
def initialize(data)
|
7
|
+
@data = data
|
8
|
+
super(
|
9
|
+
403,
|
10
|
+
:forbidden,
|
11
|
+
'This action requires to be approved.',
|
12
|
+
'CustomActionRequiresApprovalError',
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
module Ability
|
3
|
+
module Exceptions
|
4
|
+
class TriggerForbidden < ForestLiana::Errors::ExpectedError
|
5
|
+
def initialize
|
6
|
+
super(
|
7
|
+
403,
|
8
|
+
:forbidden,
|
9
|
+
'You don\'t have the permission to trigger this action',
|
10
|
+
'CustomActionTriggerForbiddenError'
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
module Ability
|
3
|
+
module Fetch
|
4
|
+
def get_permissions(route)
|
5
|
+
begin
|
6
|
+
response = ForestLiana::ForestApiRequester.get(route)
|
7
|
+
|
8
|
+
if response.is_a?(Net::HTTPOK)
|
9
|
+
JSON.parse(response.body)
|
10
|
+
else
|
11
|
+
raise "Forest API returned an #{ForestLiana::Errors::HTTPErrorHelper.format(response)}"
|
12
|
+
end
|
13
|
+
rescue => exception
|
14
|
+
FOREST_REPORTER.report exception
|
15
|
+
FOREST_LOGGER.error 'Cannot retrieve the permissions from the Forest server.'
|
16
|
+
FOREST_LOGGER.error 'Which was caused by:'
|
17
|
+
ForestLiana::Errors::ExceptionHelper.recursively_print(exception, margin: ' ', is_error: true)
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'jwt'
|
2
|
+
|
3
|
+
module ForestLiana
|
4
|
+
module Ability
|
5
|
+
module Permission
|
6
|
+
class RequestPermission
|
7
|
+
def self.decodeSignedApprovalRequest(params)
|
8
|
+
if (params[:data][:attributes][:signed_approval_request])
|
9
|
+
decode_parameters = JWT.decode(params[:data][:attributes][:signed_approval_request], ForestLiana.env_secret, true, { algorithm: 'HS256' }).try(:first)
|
10
|
+
|
11
|
+
ActionController::Parameters.new(decode_parameters)
|
12
|
+
else
|
13
|
+
params
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
module Ability
|
3
|
+
module Permission
|
4
|
+
class SmartActionChecker
|
5
|
+
|
6
|
+
def initialize(parameters, collection, smart_action, user)
|
7
|
+
@parameters = parameters
|
8
|
+
@collection = collection
|
9
|
+
@smart_action = smart_action
|
10
|
+
@user = user
|
11
|
+
end
|
12
|
+
|
13
|
+
def can_execute?
|
14
|
+
if @parameters[:data][:attributes][:signed_approval_request].present? && @smart_action['userApprovalEnabled'].include?(@user['roleId'])
|
15
|
+
can_approve?
|
16
|
+
else
|
17
|
+
can_trigger?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def can_approve?
|
24
|
+
@parameters = RequestPermission.decodeSignedApprovalRequest(@parameters)
|
25
|
+
if ((@smart_action['userApprovalConditions'].empty? || match_conditions('userApprovalConditions')) &&
|
26
|
+
(@parameters[:data][:attributes][:requester_id] != @user['id'] || @smart_action['selfApprovalEnabled'].include?(@user['roleId']))
|
27
|
+
)
|
28
|
+
return true
|
29
|
+
end
|
30
|
+
|
31
|
+
raise ForestLiana::Ability::Exceptions::TriggerForbidden.new
|
32
|
+
end
|
33
|
+
|
34
|
+
def can_trigger?
|
35
|
+
if @smart_action['triggerEnabled'].include?(@user['roleId']) && @smart_action['approvalRequired'].exclude?(@user['roleId'])
|
36
|
+
return true if @smart_action['triggerConditions'].empty? || match_conditions('triggerConditions')
|
37
|
+
elsif @smart_action['approvalRequired'].include?(@user['roleId'])
|
38
|
+
if @smart_action['approvalRequiredConditions'].empty? || match_conditions('approvalRequiredConditions')
|
39
|
+
raise ForestLiana::Ability::Exceptions::RequireApproval.new(@smart_action['userApprovalEnabled'])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
raise ForestLiana::Ability::Exceptions::TriggerForbidden.new
|
44
|
+
end
|
45
|
+
|
46
|
+
def match_conditions(condition_name)
|
47
|
+
begin
|
48
|
+
attributes = @parameters[:data][:attributes]
|
49
|
+
records = FiltersParser.new(
|
50
|
+
@smart_action[condition_name][0]['filter'].to_json,
|
51
|
+
@collection,
|
52
|
+
@parameters[:timezone],
|
53
|
+
@parameters
|
54
|
+
).apply_filters
|
55
|
+
|
56
|
+
if attributes[:all_records]
|
57
|
+
records = records.where.not(id: attributes[:all_records_ids_excluded])
|
58
|
+
else
|
59
|
+
# check if the ids are present into the request of activeRecord
|
60
|
+
records = records.where(id: attributes[:ids])
|
61
|
+
end
|
62
|
+
|
63
|
+
records.select(@collection.table_name + '.id').count == attributes[:ids].count
|
64
|
+
rescue
|
65
|
+
raise ForestLiana::Ability::Exceptions::ActionConditionError.new
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|