forest_admin_agent 1.0.0.pre.beta.31 → 1.0.0.pre.beta.33
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/lib/forest_admin_agent/http/Exceptions/conflict_error.rb +1 -2
- data/lib/forest_admin_agent/http/Exceptions/forbidden_error.rb +1 -2
- data/lib/forest_admin_agent/http/Exceptions/http_exception.rb +2 -3
- data/lib/forest_admin_agent/http/Exceptions/require_approval.rb +1 -2
- data/lib/forest_admin_agent/http/Exceptions/unprocessable_error.rb +13 -0
- data/lib/forest_admin_agent/routes/action/action.rb +22 -1
- data/lib/forest_admin_agent/services/permissions.rb +5 -2
- data/lib/forest_admin_agent/services/smart_action_checker.rb +5 -5
- data/lib/forest_admin_agent/utils/condition_tree_parser.rb +11 -11
- data/lib/forest_admin_agent/utils/context_variables.rb +4 -1
- data/lib/forest_admin_agent/utils/query_string_parser.rb +15 -1
- data/lib/forest_admin_agent/utils/schema/schema_emitter.rb +1 -1
- data/lib/forest_admin_agent/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a943d6f4ac59186bf4a2b032ffdd301d41239636408457c0d4f809633cc3ad49
|
|
4
|
+
data.tar.gz: a292ad6d5ffc8d1c65734729f0c31212a7a5157ffd5c93be2552cc19c3fbb092
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 407664d61c301ddaa40c049f52b7e58c5373ad73990f031e64f986349ca32dd45550787a3252d85f881486c61557507bfd09ec861f0f41d51bcb646250f80b56
|
|
7
|
+
data.tar.gz: 4b62bea51c7f25aaf6d2902e686b1280e8dcc019864c8c6848795846b2c9ee9aee92e0b0e53cb897b1485dbda2ed29161ea43ec0eccf4a45ec110e19c8440e38
|
|
@@ -2,11 +2,10 @@ module ForestAdminAgent
|
|
|
2
2
|
module Http
|
|
3
3
|
module Exceptions
|
|
4
4
|
class HttpException < StandardError
|
|
5
|
-
attr_reader :
|
|
5
|
+
attr_reader :status, :message, :name
|
|
6
6
|
|
|
7
|
-
def initialize(
|
|
7
|
+
def initialize(status, message, name = nil)
|
|
8
8
|
super(message)
|
|
9
|
-
@code = code
|
|
10
9
|
@status = status
|
|
11
10
|
@message = message
|
|
12
11
|
@name = name
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require 'jsonapi-serializers'
|
|
2
2
|
require 'active_support/inflector'
|
|
3
|
+
require 'jwt'
|
|
3
4
|
|
|
4
5
|
module ForestAdminAgent
|
|
5
6
|
module Routes
|
|
@@ -41,10 +42,11 @@ module ForestAdminAgent
|
|
|
41
42
|
|
|
42
43
|
def handle_request(args = {})
|
|
43
44
|
build(args)
|
|
45
|
+
args = middleware_custom_action_approval_request_data(args)
|
|
44
46
|
filter_for_caller = get_record_selection(args)
|
|
45
47
|
get_record_selection(args, include_user_scope: false)
|
|
46
48
|
|
|
47
|
-
|
|
49
|
+
@permissions.can_smart_action?(args, @collection, filter_for_caller)
|
|
48
50
|
|
|
49
51
|
raw_data = args.dig(:params, :data, :attributes, :values)
|
|
50
52
|
|
|
@@ -94,6 +96,25 @@ module ForestAdminAgent
|
|
|
94
96
|
|
|
95
97
|
private
|
|
96
98
|
|
|
99
|
+
def middleware_custom_action_approval_request_data(args)
|
|
100
|
+
raise Http::Exceptions::UnprocessableError if args.dig(:params, :data, :attributes, :requester_id)
|
|
101
|
+
|
|
102
|
+
if (signed_request = args.dig(:params, :data, :attributes, :signed_approval_request))
|
|
103
|
+
args[:params][:data][:attributes][:signed_approval_request] = decode_signed_approval_request(signed_request)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
args
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def decode_signed_approval_request(signed_request)
|
|
110
|
+
ForestAdminDatasourceToolkit::Utils::HashHelper.convert_keys(JWT.decode(
|
|
111
|
+
signed_request,
|
|
112
|
+
Facades::Container.cache(:env_secret),
|
|
113
|
+
true,
|
|
114
|
+
{ algorithm: 'HS256' }
|
|
115
|
+
)[0])
|
|
116
|
+
end
|
|
117
|
+
|
|
97
118
|
def get_record_selection(args, include_user_scope: true)
|
|
98
119
|
attributes = args.dig(:params, :data, :attributes)
|
|
99
120
|
|
|
@@ -86,7 +86,7 @@ module ForestAdminAgent
|
|
|
86
86
|
smart_action_approval = SmartActionChecker.new(
|
|
87
87
|
request[:params],
|
|
88
88
|
collection,
|
|
89
|
-
collections_data[collection.name.to_sym][:actions][action[
|
|
89
|
+
collections_data[collection.name.to_sym][:actions][action['name'].to_sym],
|
|
90
90
|
caller,
|
|
91
91
|
user_data[:roleId],
|
|
92
92
|
filter
|
|
@@ -103,6 +103,9 @@ module ForestAdminAgent
|
|
|
103
103
|
|
|
104
104
|
return nil if scope.nil?
|
|
105
105
|
|
|
106
|
+
team = get_team(caller.rendering_id)
|
|
107
|
+
user = get_user_data(caller.id)
|
|
108
|
+
|
|
106
109
|
context_variables = ContextVariables.new(team, user)
|
|
107
110
|
|
|
108
111
|
ContextVariablesInjector.inject_context_in_filter(scope, context_variables)
|
|
@@ -211,7 +214,7 @@ module ForestAdminAgent
|
|
|
211
214
|
|
|
212
215
|
return nil if actions.nil? || actions.empty?
|
|
213
216
|
|
|
214
|
-
action = actions.find { |a| a['endpoint'] == endpoint && a['
|
|
217
|
+
action = actions.find { |a| a['endpoint'] == endpoint && a['httpMethod'].casecmp(http_method).zero? }
|
|
215
218
|
|
|
216
219
|
raise ForestException, "The collection #{collection_name} does not have this smart action" if action.nil?
|
|
217
220
|
|
|
@@ -38,7 +38,8 @@ module ForestAdminAgent
|
|
|
38
38
|
def can_approve?
|
|
39
39
|
if smart_action[:userApprovalEnabled].include?(role_id) &&
|
|
40
40
|
(smart_action[:userApprovalConditions].empty? || match_conditions(:userApprovalConditions)) &&
|
|
41
|
-
(attributes[:requester_id] != caller.id ||
|
|
41
|
+
(attributes[:signed_approval_request][:data][:attributes][:requester_id] != caller.id ||
|
|
42
|
+
smart_action[:selfApprovalEnabled].include?(role_id))
|
|
42
43
|
return true
|
|
43
44
|
end
|
|
44
45
|
|
|
@@ -70,8 +71,7 @@ module ForestAdminAgent
|
|
|
70
71
|
else
|
|
71
72
|
Nodes::ConditionTreeLeaf.new(pk, 'IN', attributes[:ids])
|
|
72
73
|
end
|
|
73
|
-
|
|
74
|
-
condition = smart_action[condition_name][0]['filter']
|
|
74
|
+
condition = smart_action[condition_name][0][:filter]
|
|
75
75
|
conditional_filter = filter.override(
|
|
76
76
|
condition_tree: ConditionTreeFactory.intersect(
|
|
77
77
|
[
|
|
@@ -81,9 +81,9 @@ module ForestAdminAgent
|
|
|
81
81
|
]
|
|
82
82
|
)
|
|
83
83
|
)
|
|
84
|
-
rows = collection.aggregate(caller, conditional_filter, Aggregation.new(operation: 'Count'))
|
|
85
84
|
|
|
86
|
-
|
|
85
|
+
rows = collection.aggregate(caller, conditional_filter, Aggregation.new(operation: 'Count'))
|
|
86
|
+
(rows.empty? ? 0 : rows[0]['value']) == attributes[:ids].count
|
|
87
87
|
rescue StandardError
|
|
88
88
|
raise ConflictError.new(
|
|
89
89
|
'The conditions to trigger this action cannot be verified. Please contact an administrator.',
|
|
@@ -11,16 +11,16 @@ module ForestAdminAgent
|
|
|
11
11
|
|
|
12
12
|
def self.from_plain_object(collection, filters)
|
|
13
13
|
if leaf?(filters)
|
|
14
|
-
operator = filters[
|
|
14
|
+
operator = filters[:operator].titleize.tr(' ', '_')
|
|
15
15
|
value = parse_value(collection, filters)
|
|
16
16
|
|
|
17
|
-
return ConditionTreeLeaf.new(filters[
|
|
17
|
+
return ConditionTreeLeaf.new(filters[:field], operator, value)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
if branch?(filters)
|
|
21
|
-
aggregator = filters[
|
|
21
|
+
aggregator = filters[:aggregator].capitalize
|
|
22
22
|
conditions = []
|
|
23
|
-
filters[
|
|
23
|
+
filters[:conditions].each do |sub_tree|
|
|
24
24
|
conditions << from_plain_object(collection, sub_tree)
|
|
25
25
|
end
|
|
26
26
|
|
|
@@ -31,11 +31,11 @@ module ForestAdminAgent
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def self.parse_value(collection, leaf)
|
|
34
|
-
schema = Collection.get_field_schema(collection, leaf[
|
|
35
|
-
operator = leaf[
|
|
34
|
+
schema = Collection.get_field_schema(collection, leaf[:field])
|
|
35
|
+
operator = leaf[:operator].titleize.tr(' ', '_')
|
|
36
36
|
|
|
37
|
-
if operator == Operators::IN && leaf[
|
|
38
|
-
values = leaf[
|
|
37
|
+
if operator == Operators::IN && leaf[:field].is_a?(String)
|
|
38
|
+
values = leaf[:value].split(',').map(&:strip)
|
|
39
39
|
|
|
40
40
|
return values.map { |item| !%w[false 0 no].include?(item) } if schema.column_type == 'Boolean'
|
|
41
41
|
|
|
@@ -44,15 +44,15 @@ module ForestAdminAgent
|
|
|
44
44
|
return values
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
leaf[
|
|
47
|
+
leaf[:value]
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
def self.leaf?(filters)
|
|
51
|
-
filters.key?(
|
|
51
|
+
filters.key?(:field) && filters.key?(:operator)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
def self.branch?(filters)
|
|
55
|
-
filters.key?(
|
|
55
|
+
filters.key?(:aggregator) && filters.key?(:conditions)
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
end
|
|
@@ -29,7 +29,10 @@ module ForestAdminAgent
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
if context_variable_key.start_with?(USER_VALUE_TAG_PREFIX)
|
|
32
|
-
|
|
32
|
+
user[:tags].each do |tag|
|
|
33
|
+
match_key = context_variable_key[USER_VALUE_TAG_PREFIX.length..]
|
|
34
|
+
return tag[match_key] if tag.key?(match_key)
|
|
35
|
+
end
|
|
33
36
|
end
|
|
34
37
|
|
|
35
38
|
user[context_variable_key[USER_VALUE_PREFIX.length..].to_sym]
|
|
@@ -22,7 +22,9 @@ module ForestAdminAgent
|
|
|
22
22
|
|
|
23
23
|
return if filters.nil?
|
|
24
24
|
|
|
25
|
-
filters = JSON.parse(filters) if filters.is_a? String
|
|
25
|
+
filters = JSON.parse(filters, symbolize_names: true) if filters.is_a? String
|
|
26
|
+
# TODO: add else for convert all keys to sym
|
|
27
|
+
|
|
26
28
|
ConditionTreeParser.from_plain_object(collection, filters)
|
|
27
29
|
# TODO: ConditionTreeValidator::validate($conditionTree, $collection);
|
|
28
30
|
end
|
|
@@ -102,6 +104,18 @@ module ForestAdminAgent
|
|
|
102
104
|
|
|
103
105
|
extended != '0'
|
|
104
106
|
end
|
|
107
|
+
|
|
108
|
+
def self.parse_sort(collection, args)
|
|
109
|
+
sort_string = args.dig(:params, :sort)
|
|
110
|
+
|
|
111
|
+
return SortUtils::SortFactory.by_primary_keys(collection) unless sort_string
|
|
112
|
+
|
|
113
|
+
sort = Sort.new([
|
|
114
|
+
{ field: sort_string.gsub(/^-/, '').tr('.', ':'), ascending: !sort_string.start_with?('-') }
|
|
115
|
+
])
|
|
116
|
+
|
|
117
|
+
ForestAdminDatasourceToolkit::Validations::SortValidator.validate(collection, sort)
|
|
118
|
+
end
|
|
105
119
|
end
|
|
106
120
|
end
|
|
107
121
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: forest_admin_agent
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.0.pre.beta.
|
|
4
|
+
version: 1.0.0.pre.beta.33
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matthieu
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: exe
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2024-
|
|
12
|
+
date: 2024-03-05 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: activesupport
|
|
@@ -237,6 +237,7 @@ files:
|
|
|
237
237
|
- lib/forest_admin_agent/http/Exceptions/http_exception.rb
|
|
238
238
|
- lib/forest_admin_agent/http/Exceptions/not_found_error.rb
|
|
239
239
|
- lib/forest_admin_agent/http/Exceptions/require_approval.rb
|
|
240
|
+
- lib/forest_admin_agent/http/Exceptions/unprocessable_error.rb
|
|
240
241
|
- lib/forest_admin_agent/http/forest_admin_api_requester.rb
|
|
241
242
|
- lib/forest_admin_agent/http/router.rb
|
|
242
243
|
- lib/forest_admin_agent/routes/abstract_authenticated_route.rb
|