forest_liana 7.8.0 → 8.0.0.beta.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|