forest_admin_agent 1.0.0.pre.beta.21

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.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/CHANGELOG.md +5 -0
  4. data/README.md +35 -0
  5. data/Rakefile +10 -0
  6. data/forest_admin +1 -0
  7. data/forest_admin_agent.gemspec +48 -0
  8. data/lib/forest_admin_agent/auth/auth_manager.rb +50 -0
  9. data/lib/forest_admin_agent/auth/oauth2/forest_provider.rb +62 -0
  10. data/lib/forest_admin_agent/auth/oauth2/forest_resource_owner.rb +42 -0
  11. data/lib/forest_admin_agent/auth/oauth2/oidc_config.rb +29 -0
  12. data/lib/forest_admin_agent/auth/oidc_client_manager.rb +71 -0
  13. data/lib/forest_admin_agent/builder/agent_factory.rb +77 -0
  14. data/lib/forest_admin_agent/facades/container.rb +23 -0
  15. data/lib/forest_admin_agent/facades/whitelist.rb +13 -0
  16. data/lib/forest_admin_agent/http/Exceptions/authentication_open_id_client.rb +16 -0
  17. data/lib/forest_admin_agent/http/Exceptions/http_exception.rb +17 -0
  18. data/lib/forest_admin_agent/http/Exceptions/not_found_error.rb +15 -0
  19. data/lib/forest_admin_agent/http/forest_admin_api_requester.rb +28 -0
  20. data/lib/forest_admin_agent/http/router.rb +52 -0
  21. data/lib/forest_admin_agent/routes/abstract_authenticated_route.rb +25 -0
  22. data/lib/forest_admin_agent/routes/abstract_related_route.rb +12 -0
  23. data/lib/forest_admin_agent/routes/abstract_route.rb +27 -0
  24. data/lib/forest_admin_agent/routes/resources/count.rb +41 -0
  25. data/lib/forest_admin_agent/routes/resources/delete.rb +51 -0
  26. data/lib/forest_admin_agent/routes/resources/list.rb +38 -0
  27. data/lib/forest_admin_agent/routes/resources/related/associate_related.rb +63 -0
  28. data/lib/forest_admin_agent/routes/resources/related/count_related.rb +56 -0
  29. data/lib/forest_admin_agent/routes/resources/related/dissociate_related.rb +97 -0
  30. data/lib/forest_admin_agent/routes/resources/related/list_related.rb +54 -0
  31. data/lib/forest_admin_agent/routes/resources/related/update_related.rb +102 -0
  32. data/lib/forest_admin_agent/routes/resources/show.rb +44 -0
  33. data/lib/forest_admin_agent/routes/resources/store.rb +51 -0
  34. data/lib/forest_admin_agent/routes/resources/update.rb +42 -0
  35. data/lib/forest_admin_agent/routes/security/authentication.rb +95 -0
  36. data/lib/forest_admin_agent/routes/system/health_check.rb +22 -0
  37. data/lib/forest_admin_agent/serializer/forest_serializer.rb +176 -0
  38. data/lib/forest_admin_agent/serializer/forest_serializer_override.rb +103 -0
  39. data/lib/forest_admin_agent/services/ip_whitelist.rb +100 -0
  40. data/lib/forest_admin_agent/services/logger_service.rb +20 -0
  41. data/lib/forest_admin_agent/utils/condition_tree_parser.rb +57 -0
  42. data/lib/forest_admin_agent/utils/error_messages.rb +38 -0
  43. data/lib/forest_admin_agent/utils/id.rb +48 -0
  44. data/lib/forest_admin_agent/utils/query_string_parser.rb +89 -0
  45. data/lib/forest_admin_agent/utils/schema/frontend_filterable.rb +73 -0
  46. data/lib/forest_admin_agent/utils/schema/generator_collection.rb +35 -0
  47. data/lib/forest_admin_agent/utils/schema/generator_field.rb +183 -0
  48. data/lib/forest_admin_agent/utils/schema/schema_emitter.rb +103 -0
  49. data/lib/forest_admin_agent/version.rb +3 -0
  50. data/lib/forest_admin_agent.rb +11 -0
  51. data/sig/forest_admin_agent/auth/auth_manager.rbs +14 -0
  52. data/sig/forest_admin_agent/auth/oauth2/forest_provider.rbs +16 -0
  53. data/sig/forest_admin_agent/auth/oauth2/forest_resource_owner.rbs +15 -0
  54. data/sig/forest_admin_agent/auth/oidc_client_manager.rbs +15 -0
  55. data/sig/forest_admin_agent/builder/agent_factory.rbs +21 -0
  56. data/sig/forest_admin_agent/facades/container.rbs +9 -0
  57. data/sig/forest_admin_agent/http/router.rbs +9 -0
  58. data/sig/forest_admin_agent/routes/abstract_route.rbs +12 -0
  59. data/sig/forest_admin_agent/routes/security/authentication.rbs +14 -0
  60. data/sig/forest_admin_agent/routes/system/health_check.rbs +10 -0
  61. data/sig/forest_admin_agent.rbs +4 -0
  62. metadata +279 -0
@@ -0,0 +1,89 @@
1
+ require 'jwt'
2
+ require 'active_support/time'
3
+
4
+ module ForestAdminAgent
5
+ module Utils
6
+ class QueryStringParser
7
+ include ForestAdminDatasourceToolkit::Exceptions
8
+ include ForestAdminDatasourceToolkit::Components
9
+ include ForestAdminDatasourceToolkit::Components::Query
10
+
11
+ DEFAULT_ITEMS_PER_PAGE = '15'.freeze
12
+ DEFAULT_PAGE_TO_SKIP = '1'.freeze
13
+
14
+ def self.parse_condition_tree(collection, args)
15
+ filters = begin
16
+ args.dig(:params, :data, :attributes, :all_records_subset_query, :filters) ||
17
+ args.dig(:params, :filters) || args.dig(:params, :filter)
18
+ rescue StandardError
19
+ nil
20
+ end
21
+
22
+ return if filters.nil?
23
+
24
+ filters = JSON.parse(filters) if filters.is_a? String
25
+ ConditionTreeParser.from_plain_object(collection, filters)
26
+ # TODO: ConditionTreeValidator::validate($conditionTree, $collection);
27
+ end
28
+
29
+ def self.parse_caller(args)
30
+ unless args.dig(:headers, 'HTTP_AUTHORIZATION')
31
+ # TODO: replace by http exception
32
+ raise ForestException, 'You must be logged in to access at this resource.'
33
+ end
34
+
35
+ timezone = args[:params]['timezone']
36
+ raise ForestException, 'Missing timezone' unless timezone
37
+
38
+ raise ForestException, "Invalid timezone: #{timezone}" unless Time.find_zone(timezone)
39
+
40
+ token = args[:headers]['HTTP_AUTHORIZATION'].split[1]
41
+ token_data = JWT.decode(
42
+ token,
43
+ Facades::Container.cache(:auth_secret),
44
+ true,
45
+ { algorithm: 'HS256' }
46
+ )[0]
47
+ token_data.delete('exp')
48
+ token_data[:timezone] = timezone
49
+
50
+ Caller.new(**token_data.transform_keys(&:to_sym))
51
+ end
52
+
53
+ def self.parse_projection(collection, args)
54
+ fields = args.dig(:params, :fields, collection.name) || ''
55
+
56
+ return ProjectionFactory.all(collection) unless fields != '' && !fields.nil?
57
+
58
+ fields = fields.split(',').map do |field_name|
59
+ column = collection.fields[field_name.strip]
60
+ column.type == 'Column' ? field_name.strip : "#{field_name.strip}:#{args[:params][:fields][field_name.strip]}"
61
+ end
62
+
63
+ Projection.new(fields)
64
+ end
65
+
66
+ def self.parse_projection_with_pks(collection, args)
67
+ projection = parse_projection(collection, args)
68
+
69
+ projection.with_pks(collection)
70
+ end
71
+
72
+ def self.parse_pagination(args)
73
+ items_per_pages = args.dig(:params, :data, :attributes, :all_records_subset_query, :size) ||
74
+ args.dig(:params, :page, :size) || DEFAULT_ITEMS_PER_PAGE
75
+
76
+ page = args.dig(:params, :data, :attributes, :all_records_subset_query, :number) ||
77
+ args.dig(:params, :page, :number) || DEFAULT_PAGE_TO_SKIP
78
+
79
+ unless !items_per_pages.to_s.match(/\A[+]?\d+\z/).nil? || !page.to_s.match(/\A[+]?\d+\z/).nil?
80
+ raise ForestException, "Invalid pagination [limit: #{items_per_pages}, skip: #{page}]"
81
+ end
82
+
83
+ offset = (page.to_i - 1) * items_per_pages.to_i
84
+
85
+ Page.new(offset: offset, limit: items_per_pages.to_i)
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,73 @@
1
+ require 'digest/sha1'
2
+ require 'json'
3
+
4
+ module ForestAdminAgent
5
+ module Utils
6
+ module Schema
7
+ class FrontendFilterable
8
+ include ForestAdminDatasourceToolkit::Components::Query::ConditionTree
9
+
10
+ BASE_OPERATORS = [
11
+ Operators::EQUAL, Operators::NOT_EQUAL, Operators::PRESENT, Operators::BLANK
12
+ ].freeze
13
+
14
+ BASE_DATEONLY_OPERATORS = [
15
+ Operators::TODAY,
16
+ Operators::YESTERDAY,
17
+ Operators::PREVIOUS_X_DAYS,
18
+ Operators::PREVIOUS_WEEK,
19
+ Operators::PREVIOUS_MONTH,
20
+ Operators::PREVIOUS_QUARTER,
21
+ Operators::PREVIOUS_YEAR,
22
+ Operators::PREVIOUS_X_DAYS_TO_DATE,
23
+ Operators::PREVIOUS_WEEK_TO_DATE,
24
+ Operators::PREVIOUS_MONTH_TO_DATE,
25
+ Operators::PREVIOUS_QUARTER_TO_DATE,
26
+ Operators::PREVIOUS_YEAR_TO_DATE,
27
+ Operators::PAST,
28
+ Operators::FUTURE,
29
+ Operators::BEFORE_X_HOURS_AGO,
30
+ Operators::AFTER_X_HOURS_AGO,
31
+ Operators::BEFORE,
32
+ Operators::AFTER
33
+ ].freeze
34
+
35
+ DATE_OPERATORS = BASE_OPERATORS + BASE_DATEONLY_OPERATORS
36
+
37
+ OPERATOR_BY_TYPE = {
38
+ 'Binary' => BASE_OPERATORS,
39
+ 'Boolean' => BASE_OPERATORS,
40
+ 'Date' => DATE_OPERATORS,
41
+ 'Dateonly' => DATE_OPERATORS,
42
+ 'Uuid' => BASE_OPERATORS,
43
+ 'Enum' => BASE_OPERATORS + [Operators::IN],
44
+ 'Number' => BASE_OPERATORS + [Operators::IN, Operators::GREATER_THAN, Operators::LESS_THAN],
45
+ 'Timeonly' => BASE_OPERATORS + [Operators::GREATER_THAN, Operators::LESS_THAN],
46
+ 'String' => BASE_OPERATORS +
47
+ [
48
+ Operators::IN,
49
+ Operators::STARTS_WITH,
50
+ Operators::ENDS_WITH,
51
+ Operators::CONTAINS,
52
+ Operators::NOT_CONTAINS
53
+ ],
54
+ 'Json' => []
55
+ }.freeze
56
+
57
+ def self.filterable?(type, supported_operators = [])
58
+ needed_operators = get_required_operators(type)
59
+
60
+ !needed_operators.empty? && needed_operators.all? { |operator| supported_operators.include?(operator) }
61
+ end
62
+
63
+ def self.get_required_operators(type)
64
+ return OPERATOR_BY_TYPE[type] if type.is_a?(String) && OPERATOR_BY_TYPE.key?(type)
65
+
66
+ return ['Includes_All'] if type.is_a? Array
67
+
68
+ []
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,35 @@
1
+ module ForestAdminAgent
2
+ module Utils
3
+ module Schema
4
+ class GeneratorCollection
5
+ include ForestAdminDatasourceToolkit::Utils
6
+
7
+ def self.build_schema(collection)
8
+ {
9
+ actions: {},
10
+ fields: build_fields(collection),
11
+ icon: nil,
12
+ integration: nil,
13
+ isReadOnly: collection.fields.all? { |_k, field| field.type != 'Column' || field.is_read_only },
14
+ isSearchable: true,
15
+ isVirtual: false,
16
+ name: collection.name,
17
+ onlyForRelationships: false,
18
+ paginationType: 'page',
19
+ segments: {}
20
+ }
21
+ end
22
+
23
+ def self.build_fields(collection)
24
+ fields = collection.fields.select do |name, _field|
25
+ !ForestAdminDatasourceToolkit::Utils::Schema.foreign_key?(collection, name) ||
26
+ ForestAdminDatasourceToolkit::Utils::Schema.primary_key?(collection, name)
27
+ end
28
+
29
+ fields.map { |name, _field| GeneratorField.build_schema(collection, name) }
30
+ .sort_by { |v| v[:field] }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,183 @@
1
+ module ForestAdminAgent
2
+ module Utils
3
+ module Schema
4
+ class GeneratorField
5
+ RELATION_MAP = {
6
+ 'ManyToMany' => 'BelongsToMany',
7
+ 'ManyToOne' => 'BelongsTo',
8
+ 'OneToMany' => 'HasMany',
9
+ 'OneToOne' => 'HasOne'
10
+ }.freeze
11
+
12
+ def self.build_schema(collection, name)
13
+ type = collection.fields[name].type
14
+
15
+ case type
16
+ when 'Column'
17
+ schema = build_column_schema(collection, name)
18
+ when 'ManyToOne', 'OneToMany', 'ManyToMany', 'OneToOne'
19
+ schema = build_relation_schema(collection, name)
20
+ end
21
+
22
+ schema.sort_by { |k, _v| k }.to_h
23
+ end
24
+
25
+ class << self
26
+ private
27
+
28
+ def build_column_schema(collection, name)
29
+ column = collection.fields[name]
30
+ is_foreign_key = ForestAdminDatasourceToolkit::Utils::Schema.foreign_key?(collection, name)
31
+
32
+ {
33
+ defaultValue: column.default_value,
34
+ enums: column.enum_values.sort,
35
+ field: name,
36
+ integration: nil,
37
+ inverseOf: nil,
38
+ # isFilterable: FrontendFilterable.filterable?(column.column_type, column.filter_operators),
39
+ isFilterable: true, # TODO: remove when implementing operators decorators
40
+ isPrimaryKey: column.is_primary_key,
41
+
42
+ # When a column is a foreign key, it is readonly.
43
+ # This may sound counter-intuitive: it is so that the user don't have two fields which
44
+ # allow updating the same foreign key in the detail-view form (fk + many to one)
45
+ isReadOnly: is_foreign_key || column.is_read_only,
46
+ isRequired: column.validations.any? { |v| v[:operator] == 'Present' },
47
+ isSortable: column.is_sortable,
48
+ isVirtual: false,
49
+ reference: nil,
50
+ type: convert_column_type(column.column_type),
51
+ validations: [] # TODO: FrontendValidationUtils.convertValidationList(column),
52
+ }
53
+ end
54
+
55
+ def convert_column_type(type)
56
+ return type if type.instance_of? String
57
+
58
+ return [convert_column_type(type.first)] if type.instance_of? Array
59
+
60
+ {
61
+ fields: type.map do |key, sub_type|
62
+ {
63
+ field: key,
64
+ type: convert_column_type(sub_type)
65
+ }
66
+ end
67
+ }
68
+ end
69
+
70
+ def foreign_collection_filterable?
71
+ # TODO: implement FrontendFilterable before
72
+ true
73
+ end
74
+
75
+ def build_many_to_many_schema(relation, collection, foreign_collection, base_schema)
76
+ target_name = relation.foreign_key_target
77
+ target_field = foreign_collection.fields[target_name]
78
+ through_schema = collection.datasource.collection(relation.through_collection)
79
+ foreign_schema = through_schema.fields[relation.foreign_key]
80
+ origin_key = through_schema.fields[relation.origin_key]
81
+
82
+ base_schema.merge(
83
+ {
84
+ type: [target_field.column_type],
85
+ defaultValue: nil,
86
+ isFilterable: false,
87
+ isPrimaryKey: false,
88
+ isRequired: false,
89
+ isReadOnly: origin_key.is_read_only || foreign_schema.is_read_only,
90
+ isSortable: true,
91
+ validations: [],
92
+ reference: "#{foreign_collection.name}.#{target_name}"
93
+ }
94
+ )
95
+ end
96
+
97
+ def build_one_to_many_schema(relation, collection, foreign_collection, base_schema)
98
+ target_name = relation.origin_key_target
99
+ target_field = collection.fields[target_name]
100
+ origin_key = foreign_collection.fields[relation.origin_key]
101
+
102
+ base_schema.merge(
103
+ {
104
+ type: [target_field.column_type],
105
+ defaultValue: nil,
106
+ isFilterable: false,
107
+ isPrimaryKey: false,
108
+ isRequired: false,
109
+ isReadOnly: origin_key.is_read_only,
110
+ isSortable: true,
111
+ validations: [],
112
+ reference: "#{foreign_collection.name}.#{target_name}"
113
+ }
114
+ )
115
+ end
116
+
117
+ def build_one_to_one_schema(relation, collection, foreign_collection, base_schema)
118
+ target_field = collection.fields[relation.origin_key_target]
119
+ key_field = foreign_collection.fields[relation.origin_key]
120
+
121
+ base_schema.merge(
122
+ {
123
+ type: key_field.column_type,
124
+ defaultValue: nil,
125
+ isFilterable: foreign_collection_filterable?,
126
+ isPrimaryKey: false,
127
+ isRequired: false,
128
+ isReadOnly: key_field.is_read_only,
129
+ isSortable: target_field.is_sortable,
130
+ validations: [],
131
+ reference: "#{foreign_collection.name}.#{relation.origin_key_target}"
132
+ }
133
+ )
134
+ end
135
+
136
+ def build_many_to_one_schema(relation, collection, foreign_collection, base_schema)
137
+ key_field = collection.fields[relation.foreign_key]
138
+
139
+ base_schema.merge(
140
+ {
141
+ type: key_field.column_type,
142
+ defaultValue: key_field.default_value,
143
+ isFilterable: foreign_collection_filterable?,
144
+ isPrimaryKey: false,
145
+ isRequired: false, # TODO: check with validations
146
+ isReadOnly: key_field.is_read_only,
147
+ isSortable: key_field.is_sortable,
148
+ validations: [], # TODO: FrontendValidation::convertValidationList(foreignTargetColumn)
149
+ reference: "#{foreign_collection.name}.#{relation.foreign_key_target}"
150
+ }
151
+ )
152
+ end
153
+
154
+ def build_relation_schema(collection, name)
155
+ relation = collection.fields[name]
156
+ foreign_collection = collection.datasource.collection(relation.foreign_collection)
157
+
158
+ relation_schema = {
159
+ field: name,
160
+ enums: nil,
161
+ integration: nil,
162
+ isReadOnly: nil,
163
+ isVirtual: false,
164
+ inverseOf: nil, # TODO: CollectionUtils::getInverseRelation(collection, name)
165
+ relationship: RELATION_MAP[relation.type]
166
+ }
167
+
168
+ case relation.type
169
+ when 'ManyToMany'
170
+ build_many_to_many_schema(relation, collection, foreign_collection, relation_schema)
171
+ when 'OneToMany'
172
+ build_one_to_many_schema(relation, collection, foreign_collection, relation_schema)
173
+ when 'OneToOne'
174
+ build_one_to_one_schema(relation, collection, foreign_collection, relation_schema)
175
+ when 'ManyToOne'
176
+ build_many_to_one_schema(relation, collection, foreign_collection, relation_schema)
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,103 @@
1
+ require 'digest/sha1'
2
+ require 'json'
3
+
4
+ module ForestAdminAgent
5
+ module Utils
6
+ module Schema
7
+ class SchemaEmitter
8
+ LIANA_NAME = "forest-rails"
9
+
10
+ LIANA_VERSION = "1.0.0-beta.21"
11
+
12
+ def self.get_serialized_schema(datasource)
13
+ schema_path = Facades::Container.cache(:schema_path)
14
+ if Facades::Container.cache(:is_production)
15
+ schema = if schema_path && File.exist?(schema_path)
16
+ JSON.parse(File.read(schema_path), { symbolize_names: true })
17
+ else
18
+ # TODO: Logger::log('Warn', 'The .forestadmin-schema.json file doesn\'t exist')
19
+ {
20
+ meta: meta(Digest::SHA1.hexdigest('')),
21
+ collections: {}
22
+ }
23
+ end
24
+ else
25
+ schema = generate(datasource)
26
+ hash = Digest::SHA1.hexdigest(schema.to_json)
27
+ schema = {
28
+ meta: meta(hash),
29
+ collections: schema
30
+ }
31
+
32
+ File.write(schema_path, JSON.pretty_generate(schema))
33
+ end
34
+
35
+ serialize(schema)
36
+ end
37
+
38
+ class << self
39
+ private
40
+
41
+ def generate(datasource)
42
+ datasource.collections
43
+ .map { |_name, collection| GeneratorCollection.build_schema(collection) }
44
+ .sort_by { |collection| collection[:name] }
45
+ end
46
+
47
+ def meta(hash)
48
+ {
49
+ liana: LIANA_NAME,
50
+ liana_version: LIANA_VERSION,
51
+ stack: {
52
+ engine: 'ruby',
53
+ engine_version: RUBY_VERSION
54
+ },
55
+ schemaFileHash: hash
56
+ }
57
+ end
58
+
59
+ def serialize(schema)
60
+ data = []
61
+ included = []
62
+ schema[:collections].each do |collection|
63
+ collection_actions = collection[:actions]
64
+ collection_segments = collection[:segments]
65
+ collection.delete(:actions)
66
+ collection.delete(:segments)
67
+
68
+ included << get_smart_features_by_collection('actions', collection_actions, with_attributes: true)
69
+ included << get_smart_features_by_collection('segments', collection_segments, with_attributes: true)
70
+
71
+ data.push(
72
+ {
73
+ id: collection[:name],
74
+ type: 'collections',
75
+ attributes: collection,
76
+ relationships: {
77
+ actions: { data: get_smart_features_by_collection('actions', collection_actions) },
78
+ segments: { data: get_smart_features_by_collection('segments', collection_actions) }
79
+ }
80
+ }
81
+ )
82
+ end
83
+
84
+ {
85
+ data: data,
86
+ included: included.reject!(&:empty?),
87
+ meta: schema[:meta]
88
+ }
89
+ end
90
+
91
+ def get_smart_features_by_collection(type, data, with_attributes: false)
92
+ smart_features = []
93
+ data.each do |value|
94
+ smart_feature = { id: value[:id], type: type }
95
+ smart_feature[:attributes] = value if with_attributes
96
+ smart_features << smart_feature
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,3 @@
1
+ module ForestAdminAgent
2
+ VERSION = "1.0.0-beta.21"
3
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'forest_admin_agent/version'
2
+ require 'zeitwerk'
3
+
4
+ loader = Zeitwerk::Loader.for_gem
5
+ loader.inflector.inflect('oauth2' => 'OAuth2')
6
+ loader.setup
7
+
8
+ module ForestAdminAgent
9
+ class Error < StandardError; end
10
+ # Your code goes here...
11
+ end
@@ -0,0 +1,14 @@
1
+ module ForestAdminAgent
2
+ module Auth
3
+ class AuthManager
4
+ @oidc: ForestAdminAgent::Auth::OidcClientManager
5
+
6
+ def initialize: -> void
7
+ def start: (untyped rendering_id) -> untyped
8
+ def verify_code_and_generate_token: (untyped params) -> untyped
9
+
10
+ private
11
+ def get_rendering_id_from_state: (untyped state) -> untyped
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ module ForestAdminAgent
2
+ module Auth
3
+ module OAuth2
4
+ class ForestProvider
5
+ attr_reader rendering_id: Integer
6
+
7
+ def initialize: (Integer , Array[String]) -> void
8
+ def get_resource_owner: -> ForestResourceOwner
9
+
10
+ private
11
+ def create_resource_owner: -> ForestResourceOwner
12
+ def check_response: -> Array[String]
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ module ForestAdminAgent
2
+ module Auth
3
+ module OAuth2
4
+ class ForestResourceOwner
5
+ @data: Array[String]
6
+ @rendering_id: Integer
7
+
8
+ def initialize: (Array[String] data, Integer rendering_id) -> void
9
+ def id: -> Integer
10
+ def expiration_in_seconds: -> Integer
11
+ def make_jwt: -> String
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module ForestAdminAgent
2
+ module Auth
3
+ class OidcClientManager
4
+ TTL_CONFIG: Integer
5
+
6
+ def make_forest_provider: -> untyped
7
+
8
+ private
9
+
10
+ def setup_cache: -> { client_id: String, issuer: String, redirect_uri: String }
11
+ def register: -> Array[String]
12
+ def render_provider: -> untyped
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ module ForestAdminAgent
2
+ module Builder
3
+ class AgentFactory
4
+ TTL_CONFIG: Integer
5
+ TTL_SCHEMA: Integer
6
+ @options: untyped
7
+
8
+ attr_reader customizer: untyped
9
+ attr_reader container: untyped
10
+ attr_reader has_env_secret: untyped
11
+ def setup: (Array[string] options) -> untyped
12
+ def build: -> nil
13
+
14
+ private
15
+ def send_schema: (?force: false) -> nil
16
+ def build_container: -> untyped
17
+ def build_cache: -> nil
18
+ def build_logger: -> untyped
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ module ForestAdminAgent
2
+ module Facades
3
+ class Container
4
+ def self.instance: -> untyped
5
+ def self.config_from_cache: -> untyped
6
+ def self.get: (untyped key) -> untyped
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module ForestAdminAgent
2
+ module Http
3
+ class Router
4
+ def self.routes: -> Array[String]
5
+ def self.actions_routes: -> Array[String]
6
+ def self.api_charts_routes: -> Array[String]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ module ForestAdminAgent
2
+ module Routes
3
+ class AbstractRoute
4
+ def initialize : -> void
5
+ def routes: -> {}
6
+ def add_route: (String, String,String, String) -> void
7
+ def setup: -> AbstractRoute
8
+
9
+ def setup_routes: -> void
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ module ForestAdminAgent
2
+ module Routes
3
+ module Security
4
+ class Authentication
5
+ def setup_routes: -> Authentication
6
+ def handle_authentication: (?Hash[untyped, untyped] args) -> {content: {authorizationUrl: String}}
7
+ def handle_authentication_callback: (?Hash[untyped, untyped] args) -> {content: {token: String, tokenData: String}}
8
+ def handle_authentication_logout: (?Hash[untyped, untyped] _args) -> {content: nil, status: Integer}
9
+ def auth: -> ForestAdminAgent::Auth::AuthManager
10
+ def get_and_check_rendering_id: (Hash[untyped, untyped] params) -> Integer
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ module ForestAdminAgent
2
+ module Routes
3
+ module System
4
+ class HealthCheck
5
+ def setup_routes: -> HealthCheck
6
+ def handle_request: (?Hash[untyped, untyped] _args) -> {content: nil, status: Integer}
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,4 @@
1
+ module ForestAdminAgent
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end