forest_admin_rpc_agent 1.0.1
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 +7 -0
- data/LICENSE +674 -0
- data/bin/console +11 -0
- data/bin/forest_admin_rpc_agent +9 -0
- data/bin/setup +8 -0
- data/forest_admin_rpc_agent.gemspec +36 -0
- data/lib/forest_admin_rpc_agent/agent.rb +19 -0
- data/lib/forest_admin_rpc_agent/engine.rb +17 -0
- data/lib/forest_admin_rpc_agent/extensions/config_loader.rb +12 -0
- data/lib/forest_admin_rpc_agent/extensions/sinatra_extension.rb +32 -0
- data/lib/forest_admin_rpc_agent/facades/container.rb +29 -0
- data/lib/forest_admin_rpc_agent/middleware/authentication.rb +67 -0
- data/lib/forest_admin_rpc_agent/routes/action_execute.rb +31 -0
- data/lib/forest_admin_rpc_agent/routes/action_form.rb +49 -0
- data/lib/forest_admin_rpc_agent/routes/aggregate.rb +34 -0
- data/lib/forest_admin_rpc_agent/routes/base_route.rb +52 -0
- data/lib/forest_admin_rpc_agent/routes/chart.rb +30 -0
- data/lib/forest_admin_rpc_agent/routes/create.rb +23 -0
- data/lib/forest_admin_rpc_agent/routes/datasource_chart.rb +23 -0
- data/lib/forest_admin_rpc_agent/routes/delete.rb +28 -0
- data/lib/forest_admin_rpc_agent/routes/health_route.rb +13 -0
- data/lib/forest_admin_rpc_agent/routes/list.rb +29 -0
- data/lib/forest_admin_rpc_agent/routes/schema.rb +24 -0
- data/lib/forest_admin_rpc_agent/routes/sse.rb +80 -0
- data/lib/forest_admin_rpc_agent/routes/update.rb +26 -0
- data/lib/forest_admin_rpc_agent/sse_streamer.rb +14 -0
- data/lib/forest_admin_rpc_agent/thor/install.rb +136 -0
- data/lib/forest_admin_rpc_agent/version.rb +3 -0
- data/lib/forest_admin_rpc_agent.rb +33 -0
- metadata +122 -0
data/bin/console
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "forest_admin_rpc_agent"
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
require "irb"
|
11
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
|
+
$LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
|
3
|
+
|
4
|
+
require_relative "lib/forest_admin_rpc_agent/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "forest_admin_rpc_agent"
|
8
|
+
spec.version = ForestAdminRpcAgent::VERSION
|
9
|
+
spec.authors = ["Matthieu", "Nicolas"]
|
10
|
+
spec.email = ["matthv@gmail.com", "nicolasalexandre9@gmail.com"]
|
11
|
+
spec.homepage = "https://www.forestadmin.com"
|
12
|
+
spec.summary = "Ruby agent for Forest Admin."
|
13
|
+
spec.description = "Forest is a modern admin interface that works on all major web frameworks. This gem makes Forest
|
14
|
+
admin work on any Ruby application."
|
15
|
+
spec.license = "GPL-3.0"
|
16
|
+
spec.required_ruby_version = ">= 3.0.0"
|
17
|
+
|
18
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
19
|
+
spec.metadata["source_code_uri"] = "https://github.com/ForestAdmin/agent-ruby"
|
20
|
+
spec.metadata["changelog_uri"] = "https://github.com/ForestAdmin/agent-ruby/blob/main/CHANGELOG.md"
|
21
|
+
spec.metadata["rubygems_mfa_required"] = "false"
|
22
|
+
spec.files = Dir[
|
23
|
+
"lib/**/*.rb",
|
24
|
+
"bin/*",
|
25
|
+
"*.gemspec",
|
26
|
+
"README.md",
|
27
|
+
"LICENSE"
|
28
|
+
]
|
29
|
+
spec.bindir = "bin"
|
30
|
+
spec.executables = ["forest_admin_rpc_agent"]
|
31
|
+
spec.require_paths = ["lib"]
|
32
|
+
|
33
|
+
spec.add_dependency "dry-configurable", "~> 1.1"
|
34
|
+
spec.add_dependency "zeitwerk", "~> 2.3"
|
35
|
+
spec.add_dependency "thor", "~> 1.3"
|
36
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ForestAdminRpcAgent
|
2
|
+
class Agent < ForestAdminAgent::Builder::AgentFactory
|
3
|
+
attr_reader :rpc_collections
|
4
|
+
|
5
|
+
def setup(options)
|
6
|
+
super
|
7
|
+
@rpc_collections = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def send_schema(_force: nil)
|
11
|
+
ForestAdminRpcAgent::Facades::Container.logger.log('Info', 'Started as RPC agent, schema not sent.')
|
12
|
+
end
|
13
|
+
|
14
|
+
def mark_collections_as_rpc(*names)
|
15
|
+
@rpc_collections.push(*names)
|
16
|
+
self
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ForestAdminRpcAgent
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
isolate_namespace ForestAdminRpcAgent
|
4
|
+
|
5
|
+
config.after_initialize do
|
6
|
+
Rails.error.handle(ForestAdminDatasourceToolkit::Exceptions::ForestException) do
|
7
|
+
agent = ForestAdminRpcAgent::Agent.instance
|
8
|
+
agent.setup(ForestAdminRpcAgent.config)
|
9
|
+
|
10
|
+
# force eager loading models
|
11
|
+
Rails.application.eager_load!
|
12
|
+
|
13
|
+
ForestAdminRpcAgent::Extensions::ConfigLoader.load_configuration
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module ForestAdminRpcAgent
|
2
|
+
module Extensions
|
3
|
+
module ConfigLoader
|
4
|
+
def self.load_configuration
|
5
|
+
config_file = File.join(Dir.pwd, 'app', 'lib', 'forest_admin_rpc_agent', 'create_rpc_agent.rb')
|
6
|
+
return unless File.exist?(config_file)
|
7
|
+
|
8
|
+
ForestAdminRpcAgent::CreateRpcAgent.setup!
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
|
3
|
+
module ForestAdminRpcAgent
|
4
|
+
module Extensions
|
5
|
+
module SinatraExtension
|
6
|
+
def self.registered(app)
|
7
|
+
app.before do
|
8
|
+
agent = ForestAdminRpcAgent::Agent.instance
|
9
|
+
agent.setup(ForestAdminRpcAgent.config)
|
10
|
+
ForestAdminRpcAgent::Extensions::ConfigLoader.load_configuration
|
11
|
+
end
|
12
|
+
|
13
|
+
app.use ForestAdminRpcAgent::Middleware::Authentication
|
14
|
+
|
15
|
+
route_classes = ForestAdminRpcAgent::Routes.constants.reject { |route| route.name == 'BaseRoute' }
|
16
|
+
route_classes.each do |route|
|
17
|
+
route_class = ForestAdminRpcAgent::Routes.const_get(route)
|
18
|
+
|
19
|
+
if route_class.respond_to?(:registered)
|
20
|
+
puts "Registering #{route_class}"
|
21
|
+
route_class.registered(app)
|
22
|
+
else
|
23
|
+
ForestAdminAgent::Facades::Container.logger.log('warn',
|
24
|
+
"Skipping #{route_class} (does not respond to :registered)")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Sinatra::Base.register ForestAdminRpcAgent::Extensions::SinatraExtension
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ForestAdminRpcAgent
|
2
|
+
module Facades
|
3
|
+
class Container
|
4
|
+
def self.instance
|
5
|
+
ForestAdminRpcAgent::Agent.instance.container
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.datasource
|
9
|
+
instance.resolve(:datasource) do
|
10
|
+
ForestAdminDatasourceToolkit::Datasource.new
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.logger
|
15
|
+
instance.resolve(:logger)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.config_from_cache
|
19
|
+
instance.resolve(:cache).get('config')
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.cache(key)
|
23
|
+
raise "Key #{key} not found in container" unless config_from_cache.key?(key)
|
24
|
+
|
25
|
+
config_from_cache[key]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ForestAdminRpcAgent
|
2
|
+
module Middleware
|
3
|
+
class Authentication
|
4
|
+
ALLOWED_TIME_DIFF = 300
|
5
|
+
SIGNATURE_REUSE_WINDOW = 5
|
6
|
+
@@used_signatures = {}
|
7
|
+
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
request = Rack::Request.new(env)
|
14
|
+
signature = request.get_header('HTTP_X_SIGNATURE')
|
15
|
+
timestamp = request.get_header('HTTP_X_TIMESTAMP')
|
16
|
+
|
17
|
+
unless valid_signature?(signature, timestamp)
|
18
|
+
return [401, { 'Content-Type' => 'application/json' }, [{ error: 'Unauthorized' }.to_json]]
|
19
|
+
end
|
20
|
+
|
21
|
+
@app.call(env)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def valid_signature?(signature, timestamp)
|
27
|
+
return false if signature.nil? || timestamp.nil?
|
28
|
+
return false unless valid_timestamp?(timestamp)
|
29
|
+
|
30
|
+
expected_signature = OpenSSL::HMAC.hexdigest('SHA256', auth_secret, timestamp)
|
31
|
+
|
32
|
+
return false unless Rack::Utils.secure_compare(signature, expected_signature)
|
33
|
+
|
34
|
+
# check if this signature has already been used (replay attack)
|
35
|
+
if @@used_signatures.key?(signature)
|
36
|
+
last_used = @@used_signatures[signature]
|
37
|
+
return false if Time.now.utc.to_i - last_used > SIGNATURE_REUSE_WINDOW
|
38
|
+
end
|
39
|
+
@@used_signatures[signature] = Time.now.utc.to_i
|
40
|
+
|
41
|
+
cleanup_old_signatures
|
42
|
+
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def valid_timestamp?(timestamp)
|
47
|
+
time = begin
|
48
|
+
Time.iso8601(timestamp)
|
49
|
+
rescue StandardError
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
return false if time.nil?
|
53
|
+
|
54
|
+
(Time.now.utc.to_i - time.to_i).abs <= ALLOWED_TIME_DIFF
|
55
|
+
end
|
56
|
+
|
57
|
+
def cleanup_old_signatures
|
58
|
+
now = Time.now.utc.to_i
|
59
|
+
@@used_signatures.delete_if { |_signature, last_used| now - last_used > ALLOWED_TIME_DIFF }
|
60
|
+
end
|
61
|
+
|
62
|
+
def auth_secret
|
63
|
+
ForestAdminRpcAgent.config.auth_secret
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'jsonapi-serializers'
|
2
|
+
|
3
|
+
module ForestAdminRpcAgent
|
4
|
+
module Routes
|
5
|
+
class ActionExecute < BaseRoute
|
6
|
+
include ForestAdminDatasourceToolkit::Components::Query
|
7
|
+
include ForestAdminAgent::Utils
|
8
|
+
include ForestAdminAgent::Routes::QueryHandler
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super('rpc/:collection_name/action-execute', 'post', 'rpc_action_execute')
|
12
|
+
end
|
13
|
+
|
14
|
+
def handle_request(args)
|
15
|
+
return '{}' unless args[:params]['collection_name']
|
16
|
+
|
17
|
+
datasource = ForestAdminRpcAgent::Facades::Container.datasource
|
18
|
+
collection = datasource.get_collection(args[:params]['collection_name'])
|
19
|
+
|
20
|
+
caller = ForestAdminDatasourceToolkit::Components::Caller.new(
|
21
|
+
**args[:params]['caller'].to_h.transform_keys(&:to_sym)
|
22
|
+
)
|
23
|
+
filter = FilterFactory.from_plain_object(args[:params]['filter'])
|
24
|
+
data = args[:params]['data']
|
25
|
+
action = args[:params]['action']
|
26
|
+
|
27
|
+
collection.execute(caller, action, data, filter).to_json
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'jsonapi-serializers'
|
2
|
+
|
3
|
+
module ForestAdminRpcAgent
|
4
|
+
module Routes
|
5
|
+
class ActionForm < BaseRoute
|
6
|
+
include ForestAdminDatasourceToolkit::Components::Query
|
7
|
+
include ForestAdminAgent::Utils
|
8
|
+
include ForestAdminAgent::Routes::QueryHandler
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super('rpc/:collection_name/action-form', 'post', 'rpc_action_form')
|
12
|
+
end
|
13
|
+
|
14
|
+
def handle_request(args)
|
15
|
+
return '{}' unless args[:params]['collection_name']
|
16
|
+
|
17
|
+
datasource = ForestAdminRpcAgent::Facades::Container.datasource
|
18
|
+
collection = datasource.get_collection(args[:params]['collection_name'])
|
19
|
+
|
20
|
+
caller = if args[:params].key?('caller')
|
21
|
+
ForestAdminDatasourceToolkit::Components::Caller.new(
|
22
|
+
**args[:params]['caller'].to_h.transform_keys(&:to_sym)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
filter = FilterFactory.from_plain_object(args[:params]['filter'])
|
26
|
+
metas = args[:params]['metas'] || {}
|
27
|
+
data = args[:params]['data']
|
28
|
+
action = args[:params]['action']
|
29
|
+
|
30
|
+
form = collection.get_form(caller, action, data, filter, metas)
|
31
|
+
form = encode_file_element(form)
|
32
|
+
form.to_json
|
33
|
+
end
|
34
|
+
|
35
|
+
def encode_file_element(elements)
|
36
|
+
nested_elements = %w[Page Row]
|
37
|
+
elements.map do |element|
|
38
|
+
encode_file_element(element) if element.type == 'Layout' && nested_elements.include?(element.component)
|
39
|
+
|
40
|
+
if element.type == 'File' && element.value && element.value.is_a?(File)
|
41
|
+
element.value = ForestAdminAgent::Utils::Schema::ForestValueConverter.make_data_uri(element.value)
|
42
|
+
end
|
43
|
+
|
44
|
+
element
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'jsonapi-serializers'
|
2
|
+
|
3
|
+
module ForestAdminRpcAgent
|
4
|
+
module Routes
|
5
|
+
class Aggregate < BaseRoute
|
6
|
+
include ForestAdminDatasourceToolkit::Components::Query
|
7
|
+
include ForestAdminAgent::Utils
|
8
|
+
include ForestAdminAgent::Routes::QueryHandler
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super('rpc/:collection_name/aggregate', 'post', 'rpc_aggregate')
|
12
|
+
end
|
13
|
+
|
14
|
+
def handle_request(args)
|
15
|
+
return '{}' unless args[:params]['collection_name']
|
16
|
+
|
17
|
+
caller = ForestAdminDatasourceToolkit::Components::Caller.new(
|
18
|
+
**args[:params]['caller'].to_h.transform_keys(&:to_sym)
|
19
|
+
)
|
20
|
+
datasource = ForestAdminRpcAgent::Facades::Container.datasource
|
21
|
+
collection = datasource.get_collection(args[:params]['collection_name'])
|
22
|
+
|
23
|
+
aggregation = Aggregation.new(
|
24
|
+
operation: args[:params]['aggregation']['operation'],
|
25
|
+
field: args[:params]['aggregation']['field'],
|
26
|
+
groups: args[:params]['aggregation']['groups']
|
27
|
+
)
|
28
|
+
filter = FilterFactory.from_plain_object(args[:params]['filter'])
|
29
|
+
|
30
|
+
collection.aggregate(caller, filter, aggregation, args[:params]['limit']).to_json
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module ForestAdminRpcAgent
|
2
|
+
module Routes
|
3
|
+
class BaseRoute
|
4
|
+
def initialize(url, method, name)
|
5
|
+
@url = url
|
6
|
+
@method = method
|
7
|
+
@name = name
|
8
|
+
end
|
9
|
+
|
10
|
+
def registered(app)
|
11
|
+
if defined?(Sinatra) && (app == Sinatra::Base || app.ancestors.include?(Sinatra::Base))
|
12
|
+
register_sinatra(app)
|
13
|
+
elsif defined?(Rails) && app.is_a?(ActionDispatch::Routing::Mapper)
|
14
|
+
register_rails(app)
|
15
|
+
else
|
16
|
+
raise NotImplementedError,
|
17
|
+
"Unsupported application type: #{app.class}. #{self} works with Sinatra::Base or ActionDispatch::Routing::Mapper."
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def register_sinatra(app)
|
22
|
+
app.send(@method.to_sym, @url) do
|
23
|
+
handle_request(params)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def register_rails(router)
|
28
|
+
handler = proc do |hash|
|
29
|
+
request = ActionDispatch::Request.new(hash)
|
30
|
+
|
31
|
+
auth_middleware = ForestAdminRpcAgent::Middleware::Authentication.new(->(_env) { [200, {}, ['OK']] })
|
32
|
+
status, headers, response = auth_middleware.call(request.env)
|
33
|
+
|
34
|
+
if status == 200
|
35
|
+
params = request.query_parameters.merge(request.request_parameters)
|
36
|
+
|
37
|
+
[200, { 'Content-Type' => 'application/json' }, [handle_request({ params: params })]]
|
38
|
+
else
|
39
|
+
[status, headers, response]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
router.match @url,
|
44
|
+
defaults: { format: 'json' },
|
45
|
+
to: handler,
|
46
|
+
via: @method,
|
47
|
+
as: @name,
|
48
|
+
route_alias: @name
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'jsonapi-serializers'
|
2
|
+
|
3
|
+
module ForestAdminRpcAgent
|
4
|
+
module Routes
|
5
|
+
class Chart < BaseRoute
|
6
|
+
include ForestAdminDatasourceToolkit::Components::Query
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super('rpc/:collection_name/chart', 'post', 'rpc_chart_collection')
|
10
|
+
end
|
11
|
+
|
12
|
+
def handle_request(args)
|
13
|
+
return '{}' unless args[:params]['collection_name']
|
14
|
+
|
15
|
+
chart_name = args[:params]['name']
|
16
|
+
caller = ForestAdminDatasourceToolkit::Components::Caller.new(
|
17
|
+
**args[:params]['caller'].to_h.transform_keys(&:to_sym)
|
18
|
+
)
|
19
|
+
datasource = ForestAdminRpcAgent::Facades::Container.datasource
|
20
|
+
collection = datasource.get_collection(args[:params]['collection_name'])
|
21
|
+
|
22
|
+
collection.render_chart(
|
23
|
+
caller,
|
24
|
+
chart_name,
|
25
|
+
ForestAdminAgent::Utils::Id.unpack_id(collection, args[:params]['record_id'])
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'jsonapi-serializers'
|
2
|
+
|
3
|
+
module ForestAdminRpcAgent
|
4
|
+
module Routes
|
5
|
+
class Create < BaseRoute
|
6
|
+
def initialize
|
7
|
+
super('rpc/:collection_name/create', 'post', 'rpc_create')
|
8
|
+
end
|
9
|
+
|
10
|
+
def handle_request(args)
|
11
|
+
return '{}' unless args[:params]['collection_name']
|
12
|
+
|
13
|
+
caller = ForestAdminDatasourceToolkit::Components::Caller.new(
|
14
|
+
**args[:params]['caller'].to_h.transform_keys(&:to_sym)
|
15
|
+
)
|
16
|
+
datasource = ForestAdminRpcAgent::Facades::Container.datasource
|
17
|
+
collection = datasource.get_collection(args[:params]['collection_name'])
|
18
|
+
|
19
|
+
collection.create(caller, args[:params]['data']).to_json
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'jsonapi-serializers'
|
2
|
+
|
3
|
+
module ForestAdminRpcAgent
|
4
|
+
module Routes
|
5
|
+
class DatasourceChart < BaseRoute
|
6
|
+
def initialize
|
7
|
+
super('rpc/datasource-chart', 'post', 'rpc_chart_datasource')
|
8
|
+
end
|
9
|
+
|
10
|
+
def handle_request(args)
|
11
|
+
return '{}' unless args[:params]['chart']
|
12
|
+
|
13
|
+
chart_name = args[:params]['chart']
|
14
|
+
caller = ForestAdminDatasourceToolkit::Components::Caller.new(
|
15
|
+
**args[:params]['caller'].to_h.transform_keys(&:to_sym)
|
16
|
+
)
|
17
|
+
datasource = ForestAdminRpcAgent::Facades::Container.datasource
|
18
|
+
|
19
|
+
datasource.render_chart(caller, chart_name).to_json
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'jsonapi-serializers'
|
2
|
+
|
3
|
+
module ForestAdminRpcAgent
|
4
|
+
module Routes
|
5
|
+
class Delete < BaseRoute
|
6
|
+
include ForestAdminDatasourceToolkit::Components::Query
|
7
|
+
include ForestAdminAgent::Utils
|
8
|
+
include ForestAdminAgent::Routes::QueryHandler
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super('rpc/:collection_name/delete', 'post', 'rpc_delete')
|
12
|
+
end
|
13
|
+
|
14
|
+
def handle_request(args)
|
15
|
+
return '{}' unless args[:params]['collection_name']
|
16
|
+
|
17
|
+
caller = ForestAdminDatasourceToolkit::Components::Caller.new(
|
18
|
+
**args[:params]['caller'].to_h.transform_keys(&:to_sym)
|
19
|
+
)
|
20
|
+
datasource = ForestAdminRpcAgent::Facades::Container.datasource
|
21
|
+
collection = datasource.get_collection(args[:params]['collection_name'])
|
22
|
+
filter = FilterFactory.from_plain_object(args[:params]['filter'])
|
23
|
+
|
24
|
+
collection.delete(caller, filter).to_json
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ForestAdminRpcAgent
|
2
|
+
module Routes
|
3
|
+
class HealthRoute < BaseRoute
|
4
|
+
def initialize
|
5
|
+
super('health', 'get', 'rpc_forest')
|
6
|
+
end
|
7
|
+
|
8
|
+
def handle_request(_params)
|
9
|
+
{ status: 'ok', message: 'Forest Admin RPC Agent is running' }.to_json
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'jsonapi-serializers'
|
2
|
+
|
3
|
+
module ForestAdminRpcAgent
|
4
|
+
module Routes
|
5
|
+
class List < BaseRoute
|
6
|
+
include ForestAdminDatasourceToolkit::Components::Query
|
7
|
+
include ForestAdminAgent::Utils
|
8
|
+
include ForestAdminAgent::Routes::QueryHandler
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super('rpc/:collection_name/list', 'post', 'rpc_list')
|
12
|
+
end
|
13
|
+
|
14
|
+
def handle_request(args)
|
15
|
+
return '{}' unless args[:params]['collection_name']
|
16
|
+
|
17
|
+
caller = ForestAdminDatasourceToolkit::Components::Caller.new(
|
18
|
+
**args[:params]['caller'].to_h.transform_keys(&:to_sym)
|
19
|
+
)
|
20
|
+
datasource = ForestAdminRpcAgent::Facades::Container.datasource
|
21
|
+
collection = datasource.get_collection(args[:params]['collection_name'])
|
22
|
+
projection = Projection.new(args[:params]['projection'])
|
23
|
+
filter = FilterFactory.from_plain_object(args[:params]['filter'])
|
24
|
+
|
25
|
+
collection.list(caller, filter, projection).to_json
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ForestAdminRpcAgent
|
2
|
+
module Routes
|
3
|
+
class Schema < BaseRoute
|
4
|
+
include ForestAdminDatasourceToolkit::Components::Query::ConditionTree
|
5
|
+
include ForestAdminAgent::Utils
|
6
|
+
include ForestAdminAgent::Routes::QueryHandler
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super('rpc-schema', 'get', 'rpc_schema')
|
10
|
+
end
|
11
|
+
|
12
|
+
def handle_request(_params)
|
13
|
+
agent = ForestAdminRpcAgent::Agent.instance
|
14
|
+
schema = agent.customizer.schema
|
15
|
+
schema[:collections] = agent.customizer.datasource(ForestAdminRpcAgent::Facades::Container.logger)
|
16
|
+
.collections
|
17
|
+
.map { |_name, collection| collection.schema.merge({ name: collection.name }) }
|
18
|
+
.sort_by { |collection| collection[:name] }
|
19
|
+
|
20
|
+
schema.to_json
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|