forest_admin_agent 1.37.2 → 1.37.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 803b07951c6391fe8053f31ae3e61f9e5ca4554d566dbdb632e58ed1af347023
4
- data.tar.gz: dbcaeb6b707a998e2611aed5b48f70ac837cb7108bccdada00c18c32352f07cb
3
+ metadata.gz: e658e8812d89132182a96392c58221793cf5991bd95b4c0d3170dff0676a693c
4
+ data.tar.gz: b7cf6705ebdda5d3785e78290f1b1f4b762b1eac7b157c999bbbde4b6206b8f3
5
5
  SHA512:
6
- metadata.gz: 5f5be7f213857e22442935adae33a72e67161349f1ffc8fc54226eee9564ab732a9e69e5ff546b3f4d47abd3284609e7ba563bb9bc18a21f7bfc727da99a4fec
7
- data.tar.gz: 399f1c35b9568d590844a70aae5d01a00ed67eb6e4edade4371b05813b2ccf7ae9393477bd80565e3f65edfb7eb5870eee1aa06d5fdd775a1426996417806ba7
6
+ metadata.gz: 2feb766efd70870058a92d79ebde8cc3a41cc83452767a7478f6d5a4e66aa72346c0b1208364696fe67c5b4d4378439797240cf387d4462ea198a4f5df521152
7
+ data.tar.gz: d49ef0aca2acdb55a4c6b8d5ac58861165017f424958787064635322ff2fe961ecaa6e206ecc80c4fc495a5986434615f1aa5b9b599d62ce390733b0a4bb89e8
@@ -2,7 +2,7 @@ require 'json'
2
2
  module ForestAdminAgent
3
3
  module Routes
4
4
  module Capabilities
5
- class Collections < AbstractRoute
5
+ class Collections < AbstractAuthenticatedRoute
6
6
  include ForestAdminDatasourceToolkit::Schema
7
7
  include ForestAdminDatasourceToolkit::Schema::Relations
8
8
 
@@ -16,7 +16,8 @@ module ForestAdminAgent
16
16
  end
17
17
 
18
18
  def handle_request(args = {})
19
- datasource = ForestAdminAgent::Facades::Container.datasource
19
+ context = build(args)
20
+ datasource = context.datasource
20
21
  collections = args[:params]['collectionNames'] || []
21
22
 
22
23
  connections = datasource.live_query_connections.keys.map { |connection_name| { name: connection_name } }
@@ -37,14 +37,13 @@ module ForestAdminAgent
37
37
  end
38
38
 
39
39
  def handle_api_chart(args = {})
40
- caller = Utils::QueryStringParser.parse_caller(args)
40
+ context = build(args)
41
41
  parameters = Utils::QueryStringParser.parse_chart_parameters(args)
42
- datasource = ForestAdminAgent::Facades::Container.datasource
43
42
 
44
43
  {
45
44
  content: Serializer::ForestChartSerializer.serialize(
46
- datasource.render_chart(
47
- caller,
45
+ context.datasource.render_chart(
46
+ context.caller,
48
47
  @chart_name,
49
48
  parameters
50
49
  )
@@ -53,13 +52,12 @@ module ForestAdminAgent
53
52
  end
54
53
 
55
54
  def handle_smart_chart(args = {})
56
- caller = Utils::QueryStringParser.parse_caller(args)
55
+ context = build(args)
57
56
  parameters = Utils::QueryStringParser.parse_chart_parameters(args)
58
- datasource = ForestAdminAgent::Facades::Container.datasource
59
57
 
60
58
  {
61
- content: datasource.render_chart(
62
- caller,
59
+ content: context.datasource.render_chart(
60
+ context.caller,
63
61
  @chart_name,
64
62
  parameters
65
63
  )
@@ -50,7 +50,7 @@ module ForestAdminAgent
50
50
  condition_tree: ConditionTree::ConditionTreeFactory.intersect(
51
51
  [
52
52
  ConditionTree::Nodes::ConditionTreeLeaf.new(id, 'Equal', value),
53
- context.permissions.get_scope(context.collection)
53
+ context.permissions.get_scope(context.child_collection)
54
54
  ]
55
55
  )
56
56
  )
@@ -67,7 +67,7 @@ module ForestAdminAgent
67
67
  condition_tree: ConditionTree::ConditionTreeFactory.intersect(
68
68
  [
69
69
  ConditionTree::Nodes::ConditionTreeLeaf.new(id, 'Equal', value),
70
- context.permissions.get_scope(context.collection)
70
+ context.permissions.get_scope(context.child_collection)
71
71
  ]
72
72
  )
73
73
  )
@@ -29,7 +29,7 @@ module ForestAdminAgent
29
29
  if is_delete_mode
30
30
  context.permissions.can?(:delete, context.child_collection)
31
31
  else
32
- context.permissions.can?(:edit, context.collection)
32
+ context.permissions.can?(:edit, context.child_collection)
33
33
  end
34
34
 
35
35
  filter = get_base_foreign_filter(args, context)
@@ -22,9 +22,12 @@ module ForestAdminAgent
22
22
 
23
23
  def handle_request(args = {})
24
24
  context = build(args)
25
- context.permissions.can?(:edit, context.collection)
26
25
 
27
26
  relation = context.collection.schema[:fields][args[:params]['relation_name']]
27
+
28
+ # Must run before unpack_id: unauthorized callers get a 403, not a validation error
29
+ context.permissions.can?(:edit, mutated_collection(relation, context))
30
+
28
31
  parent_primary_key_values = Utils::Id.unpack_id(context.collection, args[:params]['id'])
29
32
 
30
33
  linked_primary_key_values = if (id = args.dig(:params, 'data', 'id'))
@@ -47,13 +50,32 @@ module ForestAdminAgent
47
50
 
48
51
  private
49
52
 
53
+ def mutated_collection(relation, context)
54
+ return context.child_collection if ['OneToOne', 'PolymorphicOneToOne'].include?(relation.type)
55
+
56
+ context.collection
57
+ end
58
+
59
+ def scoped_fk_owner_filter(parent_primary_key_values, context)
60
+ fk_owner = ConditionTree::ConditionTreeFactory.match_ids(context.collection, [parent_primary_key_values])
61
+
62
+ Filter.new(
63
+ condition_tree: ConditionTree::ConditionTreeFactory.intersect(
64
+ [
65
+ context.permissions.get_scope(context.collection),
66
+ fk_owner
67
+ ]
68
+ )
69
+ )
70
+ end
71
+
50
72
  def update_many_to_one(relation, parent_primary_key_values, linked_primary_key_values, context)
51
73
  foreign_value = if linked_primary_key_values
52
74
  Collection.get_value(context.child_collection, context.caller, linked_primary_key_values,
53
75
  relation.foreign_key_target)
54
76
  end
55
- fk_owner = ConditionTree::ConditionTreeFactory.match_ids(context.collection, [parent_primary_key_values])
56
- context.collection.update(context.caller, Filter.new(condition_tree: fk_owner),
77
+
78
+ context.collection.update(context.caller, scoped_fk_owner_filter(parent_primary_key_values, context),
57
79
  { relation.foreign_key => foreign_value })
58
80
  end
59
81
 
@@ -68,10 +90,9 @@ module ForestAdminAgent
68
90
  end
69
91
 
70
92
  polymorphic_type = context.child_collection.name.gsub('__', '::')
71
- fk_owner = ConditionTree::ConditionTreeFactory.match_ids(context.collection, [parent_primary_key_values])
72
93
  context.collection.update(
73
94
  context.caller,
74
- Filter.new(condition_tree: fk_owner),
95
+ scoped_fk_owner_filter(parent_primary_key_values, context),
75
96
  {
76
97
  relation.foreign_key => foreign_value,
77
98
  relation.foreign_key_type_field => polymorphic_type
@@ -101,7 +122,7 @@ module ForestAdminAgent
101
122
  old_fk_owner_filter = Filter.new(
102
123
  condition_tree: ConditionTree::ConditionTreeFactory.intersect(
103
124
  [
104
- context.permissions.get_scope(context.collection),
125
+ context.permissions.get_scope(context.child_collection),
105
126
  ConditionTree::Nodes::ConditionTreeBranch.new(
106
127
  'And',
107
128
  [
@@ -150,7 +171,7 @@ module ForestAdminAgent
150
171
  Filter.new(
151
172
  condition_tree: ConditionTree::ConditionTreeFactory.intersect(
152
173
  [
153
- context.permissions.get_scope(context.collection), new_fk_owner
174
+ context.permissions.get_scope(context.child_collection), new_fk_owner
154
175
  ]
155
176
  )
156
177
  ),
@@ -164,7 +185,7 @@ module ForestAdminAgent
164
185
  old_fk_owner_filter = Filter.new(
165
186
  condition_tree: ConditionTree::ConditionTreeFactory.intersect(
166
187
  [
167
- context.permissions.get_scope(context.collection),
188
+ context.permissions.get_scope(context.child_collection),
168
189
  ConditionTree::Nodes::ConditionTreeLeaf.new(
169
190
  relation.origin_key,
170
191
  ConditionTree::Operators::EQUAL,
@@ -198,7 +219,7 @@ module ForestAdminAgent
198
219
  context.caller,
199
220
  Filter.new(condition_tree: ConditionTree::ConditionTreeFactory.intersect(
200
221
  [
201
- context.permissions.get_scope(context.collection),
222
+ context.permissions.get_scope(context.child_collection),
202
223
  new_fk_owner
203
224
  ]
204
225
  )),
@@ -1,7 +1,7 @@
1
1
  module ForestAdminAgent
2
2
  module Routes
3
3
  module Security
4
- class ScopeInvalidation < AbstractRoute
4
+ class ScopeInvalidation < AbstractAuthenticatedRoute
5
5
  include ForestAdminAgent::Builder
6
6
  include ForestAdminAgent::Services
7
7
 
@@ -17,8 +17,7 @@ module ForestAdminAgent
17
17
  end
18
18
 
19
19
  def handle_request(args)
20
- # Check if user is logged
21
- Utils::QueryStringParser.parse_caller(args)
20
+ build(args)
22
21
  Permissions.invalidate_cache('forest.rendering')
23
22
 
24
23
  { content: nil, status: 204 }
@@ -51,6 +51,8 @@ module ForestAdminAgent
51
51
  true,
52
52
  { algorithm: 'HS256' }
53
53
  )[0].tap { |data| data.delete('exp') }
54
+ rescue JWT::DecodeError
55
+ raise Http::Exceptions::UnauthorizedError, 'Invalid or expired authentication token.'
54
56
  end
55
57
 
56
58
  def extract_forest_context
@@ -6,7 +6,7 @@ module ForestAdminAgent
6
6
  module Schema
7
7
  class SchemaEmitter
8
8
  LIANA_NAME = "agent-ruby"
9
- LIANA_VERSION = "1.37.2"
9
+ LIANA_VERSION = "1.37.4"
10
10
 
11
11
  def self.generate(datasource)
12
12
  datasource.collections
@@ -1,3 +1,3 @@
1
1
  module ForestAdminAgent
2
- VERSION = "1.37.2"
2
+ VERSION = "1.37.4"
3
3
  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.37.2
4
+ version: 1.37.4
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: 2026-08-10 00:00:00.000000000 Z
12
+ date: 2026-08-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport