forest_admin_agent 1.0.0.pre.beta.21 → 1.0.0.pre.beta.23
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/forest_admin_agent.gemspec +3 -1
- data/lib/forest_admin_agent/auth/oauth2/forest_provider.rb +1 -1
- data/lib/forest_admin_agent/auth/oidc_client_manager.rb +3 -2
- data/lib/forest_admin_agent/builder/agent_factory.rb +7 -9
- data/lib/forest_admin_agent/http/Exceptions/authentication_open_id_client.rb +1 -1
- data/lib/forest_admin_agent/http/Exceptions/conflict_error.rb +14 -0
- data/lib/forest_admin_agent/http/Exceptions/forbidden_error.rb +14 -0
- data/lib/forest_admin_agent/http/Exceptions/not_found_error.rb +1 -1
- data/lib/forest_admin_agent/http/Exceptions/require_approval.rb +15 -0
- data/lib/forest_admin_agent/http/forest_admin_api_requester.rb +32 -4
- data/lib/forest_admin_agent/http/router.rb +1 -0
- data/lib/forest_admin_agent/routes/abstract_authenticated_route.rb +1 -0
- data/lib/forest_admin_agent/routes/charts/charts.rb +214 -0
- data/lib/forest_admin_agent/routes/resources/count.rb +7 -4
- data/lib/forest_admin_agent/routes/resources/delete.rb +5 -1
- data/lib/forest_admin_agent/routes/resources/list.rb +9 -3
- data/lib/forest_admin_agent/routes/resources/related/associate_related.rb +10 -1
- data/lib/forest_admin_agent/routes/resources/related/count_related.rb +2 -1
- data/lib/forest_admin_agent/routes/resources/related/dissociate_related.rb +2 -0
- data/lib/forest_admin_agent/routes/resources/related/list_related.rb +9 -1
- data/lib/forest_admin_agent/routes/resources/related/update_related.rb +8 -1
- data/lib/forest_admin_agent/routes/resources/show.rb +5 -3
- data/lib/forest_admin_agent/routes/resources/store.rb +11 -10
- data/lib/forest_admin_agent/routes/resources/update.rb +4 -3
- data/lib/forest_admin_agent/serializer/forest_chart_serializer.rb +19 -0
- data/lib/forest_admin_agent/services/permissions.rb +268 -0
- data/lib/forest_admin_agent/services/smart_action_checker.rb +95 -0
- data/lib/forest_admin_agent/services/sse_cache_invalidation.rb +45 -0
- data/lib/forest_admin_agent/utils/context_variables.rb +39 -0
- data/lib/forest_admin_agent/utils/context_variables_injector.rb +53 -0
- data/lib/forest_admin_agent/utils/query_string_parser.rb +1 -0
- data/lib/forest_admin_agent/utils/schema/schema_emitter.rb +1 -1
- data/lib/forest_admin_agent/version.rb +1 -1
- data/lib/forest_admin_agent.rb +1 -0
- metadata +43 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c342682e272a5886928f4c48de0e35dbd6bcf013c4f888aa56bac238cca695da
|
4
|
+
data.tar.gz: 300d73bdac310e91c2aa4a044d095b782bd362a0fb3c6309871fad0b1fff2930
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50d05943fa75c8559e127bd181f91bb36dc64352237126381d4bd1fd769fa0e51389b74051e1f7cdc55f7c6747fbdb2c91259cf135c6e2e7e7665c5cef8cefcd
|
7
|
+
data.tar.gz: be53569ca0ad92511dc33b118693445e5a2a522faa98fd24e4d3662bf70eaa3ac7f9614cc1dccc6db444f8fe204d39db43eca1709f8efe4e528f7fef2b200ebf
|
data/forest_admin_agent.gemspec
CHANGED
@@ -34,12 +34,14 @@ admin work on any Ruby application."
|
|
34
34
|
spec.require_paths = ["lib"]
|
35
35
|
|
36
36
|
spec.add_dependency "activesupport", ">= 6.1"
|
37
|
+
spec.add_dependency "deepsort", "~> 0.4.5"
|
37
38
|
spec.add_dependency "dry-container", "~> 0.11"
|
38
39
|
spec.add_dependency "faraday", "~> 2.7"
|
40
|
+
spec.add_dependency "filecache", "~> 1.0"
|
39
41
|
spec.add_dependency "ipaddress", "~> 0.8.3"
|
40
42
|
spec.add_dependency "jsonapi-serializers", "~> 1.0"
|
41
43
|
spec.add_dependency "jwt", "~> 2.7"
|
42
|
-
spec.add_dependency "
|
44
|
+
spec.add_dependency "ld-eventsource", "~> 2.2"
|
43
45
|
spec.add_dependency "mono_logger", "~> 1.1"
|
44
46
|
spec.add_dependency "openid_connect", "~> 2.2"
|
45
47
|
spec.add_dependency "rake", "~> 13.0"
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'filecache'
|
1
2
|
require 'openid_connect'
|
2
3
|
require_relative 'oauth2/oidc_config'
|
3
4
|
require_relative 'oauth2/forest_provider'
|
@@ -18,8 +19,8 @@ module ForestAdminAgent
|
|
18
19
|
private
|
19
20
|
|
20
21
|
def setup_cache(env_secret, config_agent)
|
21
|
-
|
22
|
-
|
22
|
+
cache = FileCache.new('auth_issuer', (config_agent[:cache_dir]).to_s, TTL)
|
23
|
+
cache.get_or_set env_secret do
|
23
24
|
oidc_config = retrieve_config(config_agent[:forest_server_url])
|
24
25
|
credentials = register(
|
25
26
|
config_agent[:env_secret],
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'dry-container'
|
2
|
-
require '
|
2
|
+
require 'filecache'
|
3
3
|
|
4
4
|
module ForestAdminAgent
|
5
5
|
module Builder
|
@@ -21,7 +21,7 @@ module ForestAdminAgent
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def add_datasource(datasource)
|
24
|
-
datasource.collections.
|
24
|
+
datasource.collections.each_value { |collection| @customizer.add_collection(collection) }
|
25
25
|
self
|
26
26
|
end
|
27
27
|
|
@@ -40,9 +40,9 @@ module ForestAdminAgent
|
|
40
40
|
if !schema_is_know || force
|
41
41
|
# Logger::log('Info', 'schema was updated, sending new version');
|
42
42
|
client = ForestAdminAgent::Http::ForestAdminApiRequester.new
|
43
|
-
client.post('/forest/apimaps', schema)
|
44
|
-
schema_file_hash_cache =
|
45
|
-
schema_file_hash_cache.
|
43
|
+
client.post('/forest/apimaps', schema.to_json)
|
44
|
+
schema_file_hash_cache = FileCache.new('app', @options[:cache_dir].to_s, TTL_SCHEMA)
|
45
|
+
schema_file_hash_cache.get_or_set 'value' do
|
46
46
|
schema[:meta][:schemaFileHash]
|
47
47
|
end
|
48
48
|
@container.register(:schema_file_hash, schema_file_hash_cache)
|
@@ -59,13 +59,11 @@ module ForestAdminAgent
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def build_cache
|
62
|
-
@container.register(:cache,
|
62
|
+
@container.register(:cache, FileCache.new('app', @options[:cache_dir].to_s, TTL_SCHEMA))
|
63
63
|
return unless @has_env_secret
|
64
64
|
|
65
65
|
cache = @container.resolve(:cache)
|
66
|
-
cache.
|
67
|
-
@options.to_h
|
68
|
-
end
|
66
|
+
cache.set('config', @options.to_h)
|
69
67
|
end
|
70
68
|
|
71
69
|
def build_logger
|
@@ -5,7 +5,7 @@ module ForestAdminAgent
|
|
5
5
|
attr_reader :error, :error_description, :state
|
6
6
|
|
7
7
|
def initialize(error, error_description, state)
|
8
|
-
super
|
8
|
+
super(error, 401, error_description)
|
9
9
|
@error = error
|
10
10
|
@error_description = error_description
|
11
11
|
@state = state
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module ForestAdminAgent
|
2
|
+
module Http
|
3
|
+
module Exceptions
|
4
|
+
class ForbiddenError < HttpException
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def initialize(message, name = 'ForbiddenError')
|
8
|
+
@name = name
|
9
|
+
super(403, 'Forbidden', message)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ForestAdminAgent
|
2
|
+
module Http
|
3
|
+
module Exceptions
|
4
|
+
class RequireApproval < HttpException
|
5
|
+
attr_reader :name, :data
|
6
|
+
|
7
|
+
def initialize(message, name = 'RequireApproval', data = [])
|
8
|
+
@name = name
|
9
|
+
@data = data
|
10
|
+
super(403, 'Forbidden', message)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -3,6 +3,8 @@ require 'faraday'
|
|
3
3
|
module ForestAdminAgent
|
4
4
|
module Http
|
5
5
|
class ForestAdminApiRequester
|
6
|
+
include ForestAdminDatasourceToolkit::Exceptions
|
7
|
+
|
6
8
|
def initialize
|
7
9
|
@headers = {
|
8
10
|
'Content-Type' => 'application/json',
|
@@ -16,12 +18,38 @@ module ForestAdminAgent
|
|
16
18
|
)
|
17
19
|
end
|
18
20
|
|
19
|
-
def get(url, params)
|
20
|
-
@client.get(url, params
|
21
|
+
def get(url, params = nil)
|
22
|
+
@client.get(url, params)
|
23
|
+
end
|
24
|
+
|
25
|
+
def post(url, params = nil)
|
26
|
+
@client.post(url, params)
|
21
27
|
end
|
22
28
|
|
23
|
-
def
|
24
|
-
|
29
|
+
def handle_response_error(error)
|
30
|
+
raise error if error.is_a?(ForestException)
|
31
|
+
|
32
|
+
if error.response[:message]&.include?('certificate')
|
33
|
+
raise ForestException,
|
34
|
+
'ForestAdmin server TLS certificate cannot be verified. Please check that your system time is set properly.'
|
35
|
+
end
|
36
|
+
|
37
|
+
if error.response[:status].zero? || error.response[:status] == 502
|
38
|
+
raise ForestException, 'Failed to reach ForestAdmin server. Are you online?'
|
39
|
+
end
|
40
|
+
|
41
|
+
if error.response[:status] == 404
|
42
|
+
raise ForestException,
|
43
|
+
'ForestAdmin server failed to find the project related to the envSecret you configured. Can you check that you copied it properly in the Forest initialization?'
|
44
|
+
end
|
45
|
+
|
46
|
+
if error.response[:status] == 503
|
47
|
+
raise ForestException,
|
48
|
+
'Forest is in maintenance for a few minutes. We are upgrading your experience in the forest. We just need a few more minutes to get it right.'
|
49
|
+
end
|
50
|
+
|
51
|
+
raise ForestException,
|
52
|
+
'An unexpected error occurred while contacting the ForestAdmin server. Please contact support@forestadmin.com for further investigations.'
|
25
53
|
end
|
26
54
|
end
|
27
55
|
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
require 'jsonapi-serializers'
|
2
|
+
require 'active_support/inflector'
|
3
|
+
|
4
|
+
module ForestAdminAgent
|
5
|
+
module Routes
|
6
|
+
module Charts
|
7
|
+
class Charts < AbstractAuthenticatedRoute
|
8
|
+
include ForestAdminAgent::Builder
|
9
|
+
include ForestAdminAgent::Utils
|
10
|
+
include ForestAdminDatasourceToolkit::Components::Query
|
11
|
+
include ForestAdminDatasourceToolkit::Components::Query::ConditionTree
|
12
|
+
include ForestAdminDatasourceToolkit::Components::Charts
|
13
|
+
|
14
|
+
attr_reader :filter
|
15
|
+
|
16
|
+
FORMAT = {
|
17
|
+
Day: '%d/%m/%Y',
|
18
|
+
Week: 'W%W-%Y',
|
19
|
+
Month: '%b %y',
|
20
|
+
Year: '%Y'
|
21
|
+
}.freeze
|
22
|
+
|
23
|
+
def setup_routes
|
24
|
+
add_route('forest_chart', 'post', '/stats/:collection_name', lambda { |args|
|
25
|
+
handle_request(args)
|
26
|
+
})
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def handle_request(args = {})
|
31
|
+
build(args)
|
32
|
+
@permissions.can_chart?(args[:params])
|
33
|
+
@args = args
|
34
|
+
self.type = args[:params][:type]
|
35
|
+
@filter = Filter.new(
|
36
|
+
condition_tree: ConditionTreeFactory.intersect(
|
37
|
+
[
|
38
|
+
@permissions.get_scope(@collection),
|
39
|
+
ForestAdminAgent::Utils::QueryStringParser.parse_condition_tree(
|
40
|
+
@collection, args
|
41
|
+
)
|
42
|
+
]
|
43
|
+
)
|
44
|
+
)
|
45
|
+
|
46
|
+
inject_context_variables
|
47
|
+
|
48
|
+
{ content: Serializer::ForestChartSerializer.serialize(send(:"make_#{@type}")) }
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def type=(type)
|
54
|
+
chart_types = %w[Value Objective Pie Line Leaderboard]
|
55
|
+
unless chart_types.include?(type)
|
56
|
+
raise ForestAdminDatasourceToolkit::Exceptions::ForestException, "Invalid Chart type #{type}"
|
57
|
+
end
|
58
|
+
|
59
|
+
@type = type.downcase
|
60
|
+
end
|
61
|
+
|
62
|
+
def inject_context_variables
|
63
|
+
user = @permissions.get_user_data(@caller.id)
|
64
|
+
team = @permissions.get_team(@caller.rendering_id)
|
65
|
+
|
66
|
+
context_variables = ForestAdminAgent::Utils::ContextVariables.new(team, user,
|
67
|
+
@args[:params][:contextVariables])
|
68
|
+
return unless @args[:params][:filter]
|
69
|
+
|
70
|
+
@filter = @filter.override(condition_tree: ContextVariablesInjector.inject_context_in_filter(
|
71
|
+
@filter.condition_tree, context_variables
|
72
|
+
))
|
73
|
+
end
|
74
|
+
|
75
|
+
def make_value
|
76
|
+
value = compute_value(@filter)
|
77
|
+
previous_value = nil
|
78
|
+
is_and_aggregator = @filter.condition_tree&.try(:aggregator) == 'And'
|
79
|
+
with_count_previous = @filter.condition_tree&.some_leaf(&:use_interval_operator)
|
80
|
+
|
81
|
+
if with_count_previous && !is_and_aggregator
|
82
|
+
previous_value = compute_value(FilterFactory.get_previous_period_filter(@filter, @caller.timezone))
|
83
|
+
end
|
84
|
+
|
85
|
+
ValueChart.new(value, previous_value)
|
86
|
+
end
|
87
|
+
|
88
|
+
def make_objective
|
89
|
+
ObjectiveChart.new(compute_value(@filter))
|
90
|
+
end
|
91
|
+
|
92
|
+
def make_pie
|
93
|
+
group_field = @args[:params][:groupByFieldName]
|
94
|
+
aggregation = Aggregation.new(
|
95
|
+
operation: @args[:params][:aggregator],
|
96
|
+
field: @args[:params][:aggregateFieldName],
|
97
|
+
groups: group_field ? [{ field: group_field }] : []
|
98
|
+
)
|
99
|
+
|
100
|
+
result = @collection.aggregate(@caller, @filter, aggregation)
|
101
|
+
|
102
|
+
PieChart.new(result.map { |row| { key: row[:group][group_field], value: row[:value] } })
|
103
|
+
end
|
104
|
+
|
105
|
+
def make_line
|
106
|
+
group_by_field_name = @args[:params][:groupByFieldName]
|
107
|
+
time_range = @args[:params][:timeRange]
|
108
|
+
filter_only_with_values = @filter.override(
|
109
|
+
condition_tree: ConditionTree::ConditionTreeFactory.intersect(
|
110
|
+
[
|
111
|
+
@filter.condition_tree,
|
112
|
+
ConditionTree::Nodes::ConditionTreeLeaf.new(group_by_field_name, ConditionTree::Operators::PRESENT)
|
113
|
+
]
|
114
|
+
)
|
115
|
+
)
|
116
|
+
rows = @collection.aggregate(
|
117
|
+
@caller,
|
118
|
+
filter_only_with_values,
|
119
|
+
Aggregation.new(
|
120
|
+
operation: @args[:params][:aggregator],
|
121
|
+
field: @args[:params][:aggregateField],
|
122
|
+
groups: [{ field: group_by_field_name, operation: time_range }]
|
123
|
+
)
|
124
|
+
)
|
125
|
+
|
126
|
+
values = {}
|
127
|
+
rows.each { |row| values[row[:group][group_by_field_name]] = row[:value] }
|
128
|
+
dates = values.keys.sort
|
129
|
+
current = dates[0]
|
130
|
+
last = dates.last
|
131
|
+
result = []
|
132
|
+
while current <= last
|
133
|
+
result << {
|
134
|
+
label: current.strftime(FORMAT[time_range.to_sym]),
|
135
|
+
values: { value: values[current] || 0 }
|
136
|
+
}
|
137
|
+
current += 1.send(time_range.downcase.pluralize.to_sym)
|
138
|
+
end
|
139
|
+
|
140
|
+
LineChart.new(result)
|
141
|
+
end
|
142
|
+
|
143
|
+
def make_leaderboard
|
144
|
+
field = @collection.fields[@args[:params][:relationshipFieldName]]
|
145
|
+
|
146
|
+
if field && field.type == 'OneToMany'
|
147
|
+
inverse = ForestAdminDatasourceToolkit::Utils::Collection.get_inverse_relation(
|
148
|
+
@collection,
|
149
|
+
@args[:params][:relationshipFieldName]
|
150
|
+
)
|
151
|
+
if inverse
|
152
|
+
collection = field.foreign_collection
|
153
|
+
filter = @filter.nest(inverse)
|
154
|
+
aggregation = Aggregation.new(
|
155
|
+
operation: @args[:params][:aggregator],
|
156
|
+
field: @args[:params][:aggregateFieldName],
|
157
|
+
groups: [{ field: "#{inverse}:#{@args[:params][:labelFieldName]}" }]
|
158
|
+
)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
if field && field.type == 'ManyToMany'
|
163
|
+
origin = ForestAdminDatasourceToolkit::Utils::Collection.get_through_origin(
|
164
|
+
@collection,
|
165
|
+
@args[:params][:relationshipFieldName]
|
166
|
+
)
|
167
|
+
target = ForestAdminDatasourceToolkit::Utils::Collection.get_through_target(
|
168
|
+
@collection,
|
169
|
+
@args[:params][:relationshipFieldName]
|
170
|
+
)
|
171
|
+
if origin && target
|
172
|
+
collection = field.through_collection
|
173
|
+
filter = @filter.nest(origin)
|
174
|
+
aggregation = Aggregation.new(
|
175
|
+
operation: @args[:params][:aggregator],
|
176
|
+
field: @args[:params][:aggregateFieldName] ? "#{target}:#{@args[:params][:aggregateFieldName]}" : nil,
|
177
|
+
groups: [{ field: "#{origin}:#{@args[:params][:labelFieldName]}" }]
|
178
|
+
)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
if collection && filter && aggregation
|
183
|
+
rows = @datasource.collection(collection).aggregate(
|
184
|
+
@caller,
|
185
|
+
filter,
|
186
|
+
aggregation,
|
187
|
+
@args[:params][:limit]
|
188
|
+
)
|
189
|
+
|
190
|
+
result = rows.map do |row|
|
191
|
+
{
|
192
|
+
key: row[:group][aggregation.groups[0][:field]],
|
193
|
+
value: row[:value]
|
194
|
+
}
|
195
|
+
end
|
196
|
+
|
197
|
+
return LeaderboardChart.new(result)
|
198
|
+
end
|
199
|
+
|
200
|
+
raise ForestAdminDatasourceToolkit::Exceptions::ForestException,
|
201
|
+
'Failed to generate leaderboard chart: parameters do not match pre-requisites'
|
202
|
+
end
|
203
|
+
|
204
|
+
def compute_value(filter)
|
205
|
+
aggregation = Aggregation.new(operation: @args[:params][:aggregator],
|
206
|
+
field: @args[:params][:aggregateFieldName])
|
207
|
+
result = @collection.aggregate(@caller, filter, aggregation)
|
208
|
+
|
209
|
+
result[0][:value] || 0
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
@@ -3,8 +3,9 @@ require 'jsonapi-serializers'
|
|
3
3
|
module ForestAdminAgent
|
4
4
|
module Routes
|
5
5
|
module Resources
|
6
|
-
class Count <
|
6
|
+
class Count < AbstractAuthenticatedRoute
|
7
7
|
include ForestAdminAgent::Builder
|
8
|
+
include ForestAdminDatasourceToolkit::Components::Query::ConditionTree
|
8
9
|
def setup_routes
|
9
10
|
add_route('forest_count', 'get', '/:collection_name/count', ->(args) { handle_request(args) })
|
10
11
|
|
@@ -13,12 +14,14 @@ module ForestAdminAgent
|
|
13
14
|
|
14
15
|
def handle_request(args = {})
|
15
16
|
build(args)
|
17
|
+
@permissions.can?(:browse, @collection)
|
16
18
|
|
17
19
|
if @collection.is_countable?
|
18
|
-
|
19
|
-
|
20
|
+
filter = ForestAdminDatasourceToolkit::Components::Query::Filter.new(
|
21
|
+
condition_tree: @permissions.get_scope(@collection)
|
22
|
+
)
|
20
23
|
aggregation = ForestAdminDatasourceToolkit::Components::Query::Aggregation.new(operation: 'Count')
|
21
|
-
result = @collection.aggregate(caller, filter, aggregation)
|
24
|
+
result = @collection.aggregate(@caller, filter, aggregation)
|
22
25
|
|
23
26
|
return {
|
24
27
|
name: args[:params]['collection_name'],
|
@@ -7,6 +7,7 @@ module ForestAdminAgent
|
|
7
7
|
class Delete < AbstractAuthenticatedRoute
|
8
8
|
include ForestAdminAgent::Builder
|
9
9
|
include ForestAdminDatasourceToolkit::Components::Query
|
10
|
+
include ForestAdminDatasourceToolkit::Components::Query::ConditionTree
|
10
11
|
|
11
12
|
def setup_routes
|
12
13
|
add_route('forest_delete_bulk', 'delete', '/:collection_name', ->(args) { handle_request_bulk(args) })
|
@@ -17,6 +18,7 @@ module ForestAdminAgent
|
|
17
18
|
|
18
19
|
def handle_request(args = {})
|
19
20
|
build(args)
|
21
|
+
@permissions.can?(:delete, @collection)
|
20
22
|
id = Utils::Id.unpack_id(@collection, args[:params]['id'], with_key: true)
|
21
23
|
delete_records(args, { ids: [id], are_excluded: false })
|
22
24
|
|
@@ -25,6 +27,7 @@ module ForestAdminAgent
|
|
25
27
|
|
26
28
|
def handle_request_bulk(args = {})
|
27
29
|
build(args)
|
30
|
+
@permissions.can?(:delete, @collection)
|
28
31
|
selection_ids = Utils::Id.parse_selection_ids(@collection, args[:params], with_key: true)
|
29
32
|
delete_records(args, selection_ids)
|
30
33
|
|
@@ -38,7 +41,8 @@ module ForestAdminAgent
|
|
38
41
|
condition_tree: ConditionTree::ConditionTreeFactory.intersect(
|
39
42
|
[
|
40
43
|
Utils::QueryStringParser.parse_condition_tree(@collection, args),
|
41
|
-
condition_tree_ids
|
44
|
+
condition_tree_ids,
|
45
|
+
@permissions.get_scope(@collection)
|
42
46
|
]
|
43
47
|
)
|
44
48
|
)
|
@@ -5,6 +5,7 @@ module ForestAdminAgent
|
|
5
5
|
module Resources
|
6
6
|
class List < AbstractAuthenticatedRoute
|
7
7
|
include ForestAdminAgent::Builder
|
8
|
+
include ForestAdminDatasourceToolkit::Components::Query::ConditionTree
|
8
9
|
def setup_routes
|
9
10
|
add_route('forest_list', 'get', '/:collection_name', ->(args) { handle_request(args) })
|
10
11
|
|
@@ -13,14 +14,19 @@ module ForestAdminAgent
|
|
13
14
|
|
14
15
|
def handle_request(args = {})
|
15
16
|
build(args)
|
16
|
-
|
17
|
+
@permissions.can?(:browse, @collection)
|
17
18
|
|
18
19
|
filter = ForestAdminDatasourceToolkit::Components::Query::Filter.new(
|
19
|
-
condition_tree:
|
20
|
+
condition_tree: ConditionTreeFactory.intersect([
|
21
|
+
@permissions.get_scope(@collection),
|
22
|
+
ForestAdminAgent::Utils::QueryStringParser.parse_condition_tree(
|
23
|
+
@collection, args
|
24
|
+
)
|
25
|
+
]),
|
20
26
|
page: ForestAdminAgent::Utils::QueryStringParser.parse_pagination(args)
|
21
27
|
)
|
22
28
|
projection = ForestAdminAgent::Utils::QueryStringParser.parse_projection_with_pks(@collection, args)
|
23
|
-
records = @collection.list(caller, filter, projection)
|
29
|
+
records = @collection.list(@caller, filter, projection)
|
24
30
|
|
25
31
|
{
|
26
32
|
name: args[:params]['collection_name'],
|
@@ -8,6 +8,7 @@ module ForestAdminAgent
|
|
8
8
|
include ForestAdminAgent::Builder
|
9
9
|
include ForestAdminDatasourceToolkit::Utils
|
10
10
|
include ForestAdminDatasourceToolkit::Components::Query
|
11
|
+
|
11
12
|
def setup_routes
|
12
13
|
add_route(
|
13
14
|
'forest_related_associate',
|
@@ -21,6 +22,7 @@ module ForestAdminAgent
|
|
21
22
|
|
22
23
|
def handle_request(args = {})
|
23
24
|
build(args)
|
25
|
+
@permissions.can?(:edit, @collection)
|
24
26
|
|
25
27
|
parent_id = Utils::Id.unpack_id(@collection, args[:params]['id'], with_key: true)
|
26
28
|
target_relation_id = Utils::Id.unpack_id(@child_collection, args[:params]['data'][0]['id'], with_key: true)
|
@@ -40,7 +42,14 @@ module ForestAdminAgent
|
|
40
42
|
def associate_one_to_many(relation, parent_id, target_relation_id)
|
41
43
|
id = Schema.primary_keys(@child_collection)[0]
|
42
44
|
value = Collection.get_value(@child_collection, @caller, target_relation_id, id)
|
43
|
-
filter = Filter.new(
|
45
|
+
filter = Filter.new(
|
46
|
+
condition_tree: ConditionTree::ConditionTreeFactory.intersect(
|
47
|
+
[
|
48
|
+
ConditionTree::Nodes::ConditionTreeLeaf.new(id, 'Equal', value),
|
49
|
+
@permissions.get_scope(@collection)
|
50
|
+
]
|
51
|
+
)
|
52
|
+
)
|
44
53
|
value = Collection.get_value(@collection, @caller, parent_id, relation.origin_key_target)
|
45
54
|
|
46
55
|
@child_collection.update(@caller, filter, { relation.origin_key => value })
|
@@ -21,9 +21,10 @@ module ForestAdminAgent
|
|
21
21
|
|
22
22
|
def handle_request(args = {})
|
23
23
|
build(args)
|
24
|
+
@permissions.can?(:browse, @collection)
|
24
25
|
|
25
26
|
if @child_collection.is_countable?
|
26
|
-
filter = Filter.new
|
27
|
+
filter = Filter.new(condition_tree: @permissions.get_scope(@collection))
|
27
28
|
id = Utils::Id.unpack_id(@collection, args[:params]['id'], with_key: true)
|
28
29
|
result = Collection.aggregate_relation(
|
29
30
|
@collection,
|
@@ -21,6 +21,7 @@ module ForestAdminAgent
|
|
21
21
|
|
22
22
|
def handle_request(args = {})
|
23
23
|
build(args)
|
24
|
+
@permissions.can?(:delete, @collection)
|
24
25
|
|
25
26
|
parent_id = Utils::Id.unpack_id(@collection, args[:params]['id'], with_key: true)
|
26
27
|
is_delete_mode = !args.dig(:params, :delete).nil?
|
@@ -84,6 +85,7 @@ module ForestAdminAgent
|
|
84
85
|
Filter.new(
|
85
86
|
condition_tree: ConditionTree::ConditionTreeFactory.intersect(
|
86
87
|
[
|
88
|
+
@permissions.get_scope(@child_collection),
|
87
89
|
Utils::QueryStringParser.parse_condition_tree(@child_collection, args),
|
88
90
|
selected_ids
|
89
91
|
]
|
@@ -7,6 +7,8 @@ module ForestAdminAgent
|
|
7
7
|
class ListRelated < AbstractRelatedRoute
|
8
8
|
include ForestAdminAgent::Builder
|
9
9
|
include ForestAdminDatasourceToolkit::Utils
|
10
|
+
include ForestAdminDatasourceToolkit::Components::Query::ConditionTree
|
11
|
+
|
10
12
|
def setup_routes
|
11
13
|
add_route(
|
12
14
|
'forest_related_list',
|
@@ -20,10 +22,16 @@ module ForestAdminAgent
|
|
20
22
|
|
21
23
|
def handle_request(args = {})
|
22
24
|
build(args)
|
25
|
+
@permissions.can?(:browse, @collection)
|
23
26
|
# TODO: add csv behaviour
|
24
27
|
|
25
28
|
filter = ForestAdminDatasourceToolkit::Components::Query::Filter.new(
|
26
|
-
condition_tree:
|
29
|
+
condition_tree: ConditionTreeFactory.intersect(
|
30
|
+
[
|
31
|
+
@permissions.get_scope(@collection),
|
32
|
+
ForestAdminAgent::Utils::QueryStringParser.parse_condition_tree(@child_collection, args)
|
33
|
+
]
|
34
|
+
),
|
27
35
|
page: ForestAdminAgent::Utils::QueryStringParser.parse_pagination(args)
|
28
36
|
)
|
29
37
|
projection = ForestAdminAgent::Utils::QueryStringParser.parse_projection_with_pks(@child_collection, args)
|
@@ -21,6 +21,7 @@ module ForestAdminAgent
|
|
21
21
|
|
22
22
|
def handle_request(args = {})
|
23
23
|
build(args)
|
24
|
+
@permissions.can?(:edit, @collection)
|
24
25
|
|
25
26
|
relation = @collection.fields[args[:params]['relation_name']]
|
26
27
|
parent_id = Utils::Id.unpack_id(@collection, args[:params]['id'])
|
@@ -61,6 +62,7 @@ module ForestAdminAgent
|
|
61
62
|
old_fk_owner_filter = Filter.new(
|
62
63
|
condition_tree: ConditionTree::ConditionTreeFactory.intersect(
|
63
64
|
[
|
65
|
+
@permissions.get_scope(@collection),
|
64
66
|
ConditionTree::Nodes::ConditionTreeLeaf.new(
|
65
67
|
relation.origin_key,
|
66
68
|
ConditionTree::Operators::EQUAL,
|
@@ -91,7 +93,12 @@ module ForestAdminAgent
|
|
91
93
|
|
92
94
|
@child_collection.update(
|
93
95
|
@caller,
|
94
|
-
Filter.new(condition_tree:
|
96
|
+
Filter.new(condition_tree: ConditionTree::ConditionTreeFactory.intersect(
|
97
|
+
[
|
98
|
+
@permissions.get_scope(@collection),
|
99
|
+
new_fk_owner
|
100
|
+
]
|
101
|
+
)),
|
95
102
|
{ relation.origin_key => origin_value }
|
96
103
|
)
|
97
104
|
end
|