forest_admin_agent 1.0.0.pre.beta.21

Sign up to get free protection for your applications and to get access to all the features.
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