motor-admin 0.2.41 → 0.2.43
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/app/controllers/motor/api_configs_controller.rb +54 -0
- data/app/controllers/motor/forms_controller.rb +2 -1
- data/app/controllers/motor/queries_controller.rb +5 -1
- data/app/controllers/motor/run_api_requests_controller.rb +49 -0
- data/app/models/motor/api_config.rb +29 -0
- data/app/models/motor/form.rb +1 -0
- data/config/locales/en.yml +3 -0
- data/config/locales/es.yml +3 -0
- data/config/locales/pt.yml +3 -0
- data/config/routes.rb +2 -0
- data/lib/generators/motor/templates/install.rb +21 -0
- data/lib/generators/motor/templates/install_api_configs.rb +80 -0
- data/lib/generators/motor/upgrade_generator.rb +28 -0
- data/lib/motor/active_record_utils/types.rb +1 -1
- data/lib/motor/api_configs.rb +25 -0
- data/lib/motor/configs/build_configs_hash.rb +11 -2
- data/lib/motor/configs/load_from_cache.rb +8 -1
- data/lib/motor/configs/sync_from_hash.rb +23 -0
- data/lib/motor/forms/persistance.rb +21 -1
- data/lib/motor/net_http_utils.rb +14 -2
- data/lib/motor/queries/persistance.rb +17 -0
- data/lib/motor/version.rb +1 -1
- data/lib/motor.rb +1 -0
- data/ui/dist/{main-f7a83db6d8381e2638a1.css.gz → main-90db17316da397cbfa9c.css.gz} +0 -0
- data/ui/dist/{main-f7a83db6d8381e2638a1.js.gz → main-90db17316da397cbfa9c.js.gz} +0 -0
- data/ui/dist/manifest.json +5 -5
- metadata +10 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 89d36e62222311f43cf9df24d7d090d72cb067e9cc713431ff2f7ce39ed8079c
|
4
|
+
data.tar.gz: 40f0520672effff61094e2518afcb216c6da4c2402749bac024648a5a8c491e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89e962e2d87c0171a38961d1f1d0ede97021d5eb8bb0ba071b92d3c114a919d201f11dd25647793efd656823fc7b19c7e913c51a73b7e69b7f472f8772a59fa5
|
7
|
+
data.tar.gz: 38d3105d72a4aca9fa91f0096e92d7c4ef015e0544e877ceb7b844eac6617cbdc1c25a6df20772358b5a93b29b661985d6112719cfae9e62737499306b05c695
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Motor
|
4
|
+
class ApiConfigsController < ApiBaseController
|
5
|
+
wrap_parameters :data, except: %i[include fields]
|
6
|
+
|
7
|
+
before_action :find_or_initialize_api_config, only: :create
|
8
|
+
load_and_authorize_resource
|
9
|
+
|
10
|
+
def index
|
11
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@api_configs.active.order(:id), params, current_ability) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def create
|
15
|
+
@api_config.save!
|
16
|
+
|
17
|
+
Motor::Configs::WriteToFile.call
|
18
|
+
|
19
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@api_config, params, current_ability) }
|
20
|
+
rescue ActiveRecord::RecordNotUnique
|
21
|
+
find_or_initialize_api_config
|
22
|
+
|
23
|
+
retry
|
24
|
+
end
|
25
|
+
|
26
|
+
def destroy
|
27
|
+
@api_config&.update!(deleted_at: Time.current)
|
28
|
+
|
29
|
+
Motor::Configs::WriteToFile.call
|
30
|
+
|
31
|
+
head :ok
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def find_or_initialize_api_config
|
37
|
+
name, url, description, preferences, credentials =
|
38
|
+
api_config_params.values_at(:name, :url, :description, :preferences, :credentials)
|
39
|
+
|
40
|
+
@api_config =
|
41
|
+
Motor::ApiConfig.find_or_initialize_by(name: name).tap do |config|
|
42
|
+
config.url = url.delete_suffix('/')
|
43
|
+
config.description = description
|
44
|
+
config.preferences.merge!(preferences)
|
45
|
+
config.credentials.merge!(credentials)
|
46
|
+
config.deleted_at = nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def api_config_params
|
51
|
+
params.require(:data).permit(:name, :url, :description, preferences: {}, credentials: {})
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -54,7 +54,8 @@ module Motor
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def form_params
|
57
|
-
params.require(:data).permit(:name, :description, :api_path, :http_method,
|
57
|
+
params.require(:data).permit(:name, :description, :api_path, :http_method,
|
58
|
+
:api_config_name, preferences: {}, tags: [])
|
58
59
|
end
|
59
60
|
end
|
60
61
|
end
|
@@ -21,7 +21,11 @@ module Motor
|
|
21
21
|
if Motor::Queries::Persistance.name_already_exists?(@query)
|
22
22
|
render json: { errors: [{ source: 'name', detail: 'Name already exists' }] }, status: :unprocessable_entity
|
23
23
|
else
|
24
|
-
ApplicationRecord.transaction
|
24
|
+
ApplicationRecord.transaction do
|
25
|
+
Motor::Queries::Persistance.assign_or_create_api_config!(@query)
|
26
|
+
@query.save!
|
27
|
+
end
|
28
|
+
|
25
29
|
Motor::Configs::WriteToFile.call
|
26
30
|
|
27
31
|
render json: { data: Motor::ApiQuery::BuildJson.call(@query, params, current_ability) }
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Motor
|
4
|
+
class RunApiRequestsController < ApiBaseController
|
5
|
+
JWT_TTL = 2.hours
|
6
|
+
|
7
|
+
wrap_parameters :data
|
8
|
+
|
9
|
+
def show
|
10
|
+
respond_with_result
|
11
|
+
end
|
12
|
+
|
13
|
+
def create
|
14
|
+
respond_with_result
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def respond_with_result
|
20
|
+
response = Motor::ApiConfigs.run(find_or_initialize_api_config,
|
21
|
+
method: request_params[:method],
|
22
|
+
path: request_params[:path],
|
23
|
+
body: request_params[:params],
|
24
|
+
params: request_params[:body],
|
25
|
+
headers: { 'Authorization' => "Bearer #{current_user_jwt}" })
|
26
|
+
|
27
|
+
self.response_body = response.body
|
28
|
+
self.status = response.code.to_i
|
29
|
+
end
|
30
|
+
|
31
|
+
def find_or_initialize_api_config
|
32
|
+
Motor::ApiConfig.find_by(name: request_params[:api_config_name]) ||
|
33
|
+
Motor::ApiConfig.new(url: request_params[:api_config_name])
|
34
|
+
end
|
35
|
+
|
36
|
+
def current_user_jwt
|
37
|
+
return '' unless defined?(JWT)
|
38
|
+
return '' unless current_user
|
39
|
+
|
40
|
+
payload = { uid: current_user.id, email: current_user.email, exp: JWT_TTL.from_now.to_i }
|
41
|
+
|
42
|
+
JWT.encode(payload, Rails.application.secrets.secret_key_base)
|
43
|
+
end
|
44
|
+
|
45
|
+
def request_params
|
46
|
+
params.require(:data).permit!
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Motor
|
4
|
+
class ApiConfig < ::Motor::ApplicationRecord
|
5
|
+
unless table_exists?
|
6
|
+
puts
|
7
|
+
puts ' => Run `rails g motor:upgrade && rake db:migrate` to perform data migration and enable the latest features'
|
8
|
+
puts
|
9
|
+
end
|
10
|
+
|
11
|
+
encrypts :credentials if defined?(::Motor::EncryptedConfig)
|
12
|
+
|
13
|
+
serialize :credentials, Motor::HashSerializer
|
14
|
+
serialize :preferences, Motor::HashSerializer
|
15
|
+
|
16
|
+
attribute :preferences, default: -> { HashWithIndifferentAccess.new }
|
17
|
+
attribute :credentials, default: -> { HashWithIndifferentAccess.new }
|
18
|
+
|
19
|
+
has_one :form, dependent: nil, foreign_key: :api_config_name, primary_key: :name, inverse_of: :api_config
|
20
|
+
|
21
|
+
scope :active, -> { where(deleted_at: nil) }
|
22
|
+
|
23
|
+
def headers
|
24
|
+
credentials.fetch(:headers, []).each_with_object({}) do |item, acc|
|
25
|
+
acc[item[:key]] = item[:value]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/app/models/motor/form.rb
CHANGED
@@ -5,6 +5,7 @@ module Motor
|
|
5
5
|
audited
|
6
6
|
|
7
7
|
belongs_to :author, polymorphic: true, optional: true
|
8
|
+
belongs_to :api_config, foreign_key: :api_config_name, primary_key: :name, inverse_of: :form
|
8
9
|
|
9
10
|
has_many :taggable_tags, as: :taggable, dependent: :destroy
|
10
11
|
has_many :tags, through: :taggable_tags, class_name: 'Motor::Tag'
|
data/config/locales/en.yml
CHANGED
data/config/locales/es.yml
CHANGED
data/config/locales/pt.yml
CHANGED
data/config/routes.rb
CHANGED
@@ -14,6 +14,8 @@ Motor::Admin.routes.draw do
|
|
14
14
|
resources :resource_default_queries, only: %i[show], param: 'resource'
|
15
15
|
resources :schema, only: %i[index show], param: 'resource'
|
16
16
|
resources :dashboards, only: %i[index show create update destroy]
|
17
|
+
resource :run_api_request, only: %i[show create]
|
18
|
+
resources :api_configs, only: %i[index create destroy]
|
17
19
|
resources :forms, only: %i[index show create update destroy]
|
18
20
|
resources :alerts, only: %i[index show create update destroy]
|
19
21
|
resources :icons, only: %i[index]
|
@@ -44,6 +44,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
|
|
44
44
|
t.column :author_id, :bigint
|
45
45
|
t.column :author_type, :string
|
46
46
|
t.column :deleted_at, :datetime
|
47
|
+
t.column :api_config_name, :string, null: false
|
47
48
|
|
48
49
|
t.timestamps
|
49
50
|
|
@@ -138,6 +139,22 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
|
|
138
139
|
t.column :created_at, :datetime
|
139
140
|
end
|
140
141
|
|
142
|
+
create_table :motor_api_configs do |t|
|
143
|
+
t.column :name, :string, null: false
|
144
|
+
t.column :url, :string, null: false
|
145
|
+
t.column :preferences, :text, null: false
|
146
|
+
t.column :credentials, :text, null: false
|
147
|
+
t.column :description, :text
|
148
|
+
t.column :deleted_at, :datetime
|
149
|
+
|
150
|
+
t.timestamps
|
151
|
+
|
152
|
+
t.index 'name',
|
153
|
+
name: 'motor_api_configs_name_unique_index',
|
154
|
+
unique: true,
|
155
|
+
where: 'deleted_at IS NULL'
|
156
|
+
end
|
157
|
+
|
141
158
|
add_index :motor_audits, %i[auditable_type auditable_id version], name: 'motor_auditable_index'
|
142
159
|
add_index :motor_audits, %i[associated_type associated_id], name: 'motor_auditable_associated_index'
|
143
160
|
add_index :motor_audits, %i[user_id user_type], name: 'motor_auditable_user_index'
|
@@ -152,6 +169,10 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
|
|
152
169
|
name: '⭐ Star on GitHub',
|
153
170
|
path: 'https://github.com/motor-admin/motor-admin-rails'
|
154
171
|
}].to_json)
|
172
|
+
|
173
|
+
model.table_name = 'motor_api_configs'
|
174
|
+
|
175
|
+
model.create!(name: 'origin', path: '/')
|
155
176
|
end
|
156
177
|
|
157
178
|
def self.down
|
@@ -0,0 +1,80 @@
|
|
1
|
+
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
2
|
+
class MotorApiConfig < ActiveRecord::Base
|
3
|
+
self.table_name = 'motor_api_configs'
|
4
|
+
|
5
|
+
encrypts :credentials if defined?(::Motor::EncryptedConfig)
|
6
|
+
|
7
|
+
serialize :credentials, Motor::HashSerializer
|
8
|
+
serialize :preferences, Motor::HashSerializer
|
9
|
+
|
10
|
+
attribute :preferences, default: -> { HashWithIndifferentAccess.new }
|
11
|
+
attribute :credentials, default: -> { HashWithIndifferentAccess.new }
|
12
|
+
end
|
13
|
+
|
14
|
+
class MotorForm < ActiveRecord::Base
|
15
|
+
self.table_name = 'motor_forms'
|
16
|
+
end
|
17
|
+
|
18
|
+
class MotorQuery < ActiveRecord::Base
|
19
|
+
self.table_name = 'motor_queries'
|
20
|
+
|
21
|
+
serialize :preferences, Motor::HashSerializer
|
22
|
+
end
|
23
|
+
|
24
|
+
def up
|
25
|
+
create_table :motor_api_configs do |t|
|
26
|
+
t.column :name, :string, null: false
|
27
|
+
t.column :url, :string, null: false
|
28
|
+
t.column :preferences, :text, null: false
|
29
|
+
t.column :credentials, :text, null: false
|
30
|
+
t.column :description, :text
|
31
|
+
t.column :deleted_at, :datetime
|
32
|
+
|
33
|
+
t.timestamps
|
34
|
+
|
35
|
+
t.index 'name',
|
36
|
+
name: 'motor_api_configs_name_unique_index',
|
37
|
+
unique: true,
|
38
|
+
where: 'deleted_at IS NULL'
|
39
|
+
end
|
40
|
+
|
41
|
+
add_column :motor_forms, :api_config_name, :string
|
42
|
+
|
43
|
+
MotorForm.all.each do |form|
|
44
|
+
if form.api_path.starts_with?('http')
|
45
|
+
url = form.api_path[%r{\Ahttps?://[^/]+}]
|
46
|
+
|
47
|
+
form.preferences[:default_values_api_path]&.delete(url)
|
48
|
+
form.update!(api_config_name: MotorApiConfig.find_or_create_by!(name: url, url: url).name,
|
49
|
+
api_path: form.api_path.delete(url))
|
50
|
+
else
|
51
|
+
form.update!(api_config_name: MotorApiConfig.find_or_create_by!(name: 'origin', url: '/').name)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
MotorQuery.all.each do |query|
|
56
|
+
next if query.preferences['api_path'].blank?
|
57
|
+
|
58
|
+
if query.preferences['api_path'].starts_with?('http')
|
59
|
+
url = query.preferences['api_path'][%r{\Ahttps?://[^/]+}]
|
60
|
+
|
61
|
+
query.preferences['api_path'].delete(url)
|
62
|
+
|
63
|
+
query.preferences['api_config_name'] = MotorApiConfig.find_or_create_by!(name: url, url: url).name
|
64
|
+
else
|
65
|
+
query.preferences['api_config_name'] = MotorApiConfig.find_or_create_by!(name: 'origin', url: '/').name
|
66
|
+
end
|
67
|
+
|
68
|
+
query.save!
|
69
|
+
end
|
70
|
+
|
71
|
+
change_column_null :motor_forms, :api_config_name, false
|
72
|
+
|
73
|
+
MotorApiConfig.find_or_create_by!(name: 'origin', url: '/')
|
74
|
+
end
|
75
|
+
|
76
|
+
def down
|
77
|
+
remove_column :motor_forms, :api_config_name
|
78
|
+
drop_table :motor_api_configs
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators'
|
4
|
+
require 'rails/generators/migration'
|
5
|
+
require 'active_record'
|
6
|
+
require 'rails/generators/active_record'
|
7
|
+
require 'generators/motor/migration'
|
8
|
+
|
9
|
+
module Motor
|
10
|
+
module Generators
|
11
|
+
class UpgradeGenerator < Rails::Generators::Base
|
12
|
+
include Rails::Generators::Migration
|
13
|
+
extend Motor::Generators::Migration
|
14
|
+
|
15
|
+
source_root File.expand_path('templates', __dir__)
|
16
|
+
|
17
|
+
def copy_migration
|
18
|
+
if Motor::ApiConfig.table_exists?
|
19
|
+
puts 'The latest Motor Admin features are already configured'
|
20
|
+
else
|
21
|
+
migration_template 'install_api_configs.rb', 'db/migrate/install_motor_api_configs.rb'
|
22
|
+
|
23
|
+
puts 'Run `rake db:migrate` to update DB schema'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -53,7 +53,7 @@ module Motor
|
|
53
53
|
|
54
54
|
type_map = connection_class.connection.send(:type_map)
|
55
55
|
|
56
|
-
type_map.instance_variable_get(
|
56
|
+
type_map.instance_variable_get(:@mapping).map do |name, type|
|
57
57
|
next unless name.is_a?(String)
|
58
58
|
|
59
59
|
[type.call.class.to_s, name]
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Motor
|
4
|
+
module ApiConfigs
|
5
|
+
METHODS = %w[get post put delete].freeze
|
6
|
+
|
7
|
+
InvalidHttpMethod = Class.new(StandardError)
|
8
|
+
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def run(api_config, method: nil, path: nil, body: nil, params: {}, headers: {})
|
12
|
+
method ||= 'get'
|
13
|
+
|
14
|
+
raise InvalidHttpMethod unless METHODS.include?(method.downcase)
|
15
|
+
|
16
|
+
Motor::NetHttpUtils.public_send(
|
17
|
+
method.downcase.to_sym,
|
18
|
+
api_config.url.to_s.sub(%r{/?\z}, '/') + path.delete_prefix('/'),
|
19
|
+
params,
|
20
|
+
headers.merge(api_config.headers),
|
21
|
+
body
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -5,6 +5,7 @@ module Motor
|
|
5
5
|
module BuildConfigsHash
|
6
6
|
module_function
|
7
7
|
|
8
|
+
# rubocop:disable Metrics/AbcSize
|
8
9
|
def call
|
9
10
|
cache_keys = LoadFromCache.load_cache_keys
|
10
11
|
|
@@ -16,9 +17,11 @@ module Motor
|
|
16
17
|
queries: build_queries_hash(cache_keys[:queries]),
|
17
18
|
dashboards: build_dashboards_hash(cache_keys[:dashboards]),
|
18
19
|
forms: build_forms_hash(cache_keys[:forms]),
|
19
|
-
alerts: build_alerts_hash(cache_keys[:alerts])
|
20
|
+
alerts: build_alerts_hash(cache_keys[:alerts]),
|
21
|
+
api_configs: build_api_configs_hash(cache_keys[:api_configs])
|
20
22
|
)
|
21
23
|
end
|
24
|
+
# rubocop:enable Metrics/AbcSize
|
22
25
|
|
23
26
|
def build_queries_hash(cache_key = nil)
|
24
27
|
Motor::Configs::LoadFromCache.load_queries(cache_key: cache_key).sort_by(&:id).map do |query|
|
@@ -43,11 +46,17 @@ module Motor
|
|
43
46
|
|
44
47
|
def build_forms_hash(cache_key = nil)
|
45
48
|
Motor::Configs::LoadFromCache.load_forms(cache_key: cache_key).sort_by(&:id).map do |form|
|
46
|
-
form.slice(%i[id name http_method api_path description preferences])
|
49
|
+
form.slice(%i[id name http_method api_path description preferences api_config_name])
|
47
50
|
.merge(tags: form.tags.map(&:name), updated_at: form.updated_at.to_time)
|
48
51
|
end
|
49
52
|
end
|
50
53
|
|
54
|
+
def build_api_configs_hash(cache_key = nil)
|
55
|
+
Motor::Configs::LoadFromCache.load_api_configs(cache_key: cache_key).sort_by(&:id).map do |config|
|
56
|
+
config.slice(%i[id name url preferences description]).merge(updated_at: config.updated_at.to_time)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
51
60
|
def build_configs_hash(cache_key = nil)
|
52
61
|
Motor::Configs::LoadFromCache.load_configs(cache_key: cache_key).sort_by(&:key).map do |config|
|
53
62
|
{
|
@@ -68,6 +68,12 @@ module Motor
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
+
def load_api_configs(cache_key: nil)
|
72
|
+
maybe_fetch_from_cache('forms', cache_key) do
|
73
|
+
Motor::ApiConfig.all.active.load
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
71
77
|
def maybe_fetch_from_cache(type, cache_key)
|
72
78
|
return yield unless cache_key
|
73
79
|
|
@@ -95,7 +101,8 @@ module Motor
|
|
95
101
|
Motor::Dashboard.select("'dashboards', MAX(updated_at)").to_sql,
|
96
102
|
Motor::Alert.select("'alerts', MAX(updated_at)").to_sql,
|
97
103
|
Motor::Query.select("'queries', MAX(updated_at)").to_sql,
|
98
|
-
Motor::Form.select("'forms', MAX(updated_at)").to_sql
|
104
|
+
Motor::Form.select("'forms', MAX(updated_at)").to_sql,
|
105
|
+
Motor::ApiConfig.select("'api_configs', MAX(updated_at)").to_sql
|
99
106
|
].join(' UNION ')
|
100
107
|
end
|
101
108
|
end
|
@@ -17,6 +17,7 @@ module Motor
|
|
17
17
|
sync_forms(configs_hash)
|
18
18
|
sync_configs(configs_hash)
|
19
19
|
sync_resources(configs_hash)
|
20
|
+
sync_api_configs(configs_hash)
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
@@ -68,6 +69,28 @@ module Motor
|
|
68
69
|
end
|
69
70
|
end
|
70
71
|
|
72
|
+
def sync_api_configs(configs_hash)
|
73
|
+
return if configs_hash[:api_configs].blank?
|
74
|
+
|
75
|
+
configs_index = Motor::Configs::LoadFromCache.load_api_configs.index_by(&:name)
|
76
|
+
|
77
|
+
configs_hash[:api_configs].each do |attrs|
|
78
|
+
record = configs_index[attrs[:name]] || Motor::ApiConfig.new
|
79
|
+
|
80
|
+
next if record.updated_at && attrs[:updated_at] <= record.updated_at
|
81
|
+
|
82
|
+
record.update!(attrs.merge(deleted_at: nil))
|
83
|
+
end
|
84
|
+
|
85
|
+
archive_api_configs(configs_index, configs_hash[:api_configs])
|
86
|
+
end
|
87
|
+
|
88
|
+
def archive_api_configs(configs_index, api_configs)
|
89
|
+
configs_index.except(*api_configs.pluck('name')).each_value do |config|
|
90
|
+
config.update!(deleted_at: Time.current) if config.deleted_at.blank?
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
71
94
|
def sync_resources(configs_hash)
|
72
95
|
resources_index = Motor::Configs::LoadFromCache.load_resources.index_by(&:name)
|
73
96
|
|
@@ -38,6 +38,7 @@ module Motor
|
|
38
38
|
|
39
39
|
ApplicationRecord.transaction do
|
40
40
|
archive_with_existing_name(form) if force_replace
|
41
|
+
find_or_assign_api_config(form)
|
41
42
|
|
42
43
|
form.save!
|
43
44
|
end
|
@@ -50,12 +51,31 @@ module Motor
|
|
50
51
|
end
|
51
52
|
|
52
53
|
def assign_attributes(form, params)
|
53
|
-
form.assign_attributes(params.slice(:name, :description, :api_path, :http_method, :preferences
|
54
|
+
form.assign_attributes(params.slice(:name, :description, :api_path, :http_method, :preferences,
|
55
|
+
:api_config_name))
|
54
56
|
form.updated_at = [params[:updated_at], Time.current].min if params[:updated_at].present?
|
55
57
|
|
58
|
+
find_or_assign_api_config(form)
|
59
|
+
|
56
60
|
Motor::Tags.assign_tags(form, params[:tags])
|
57
61
|
end
|
58
62
|
|
63
|
+
def find_or_assign_api_config(form)
|
64
|
+
return if form.api_config.present?
|
65
|
+
|
66
|
+
config = Motor::ApiConfig.find_by(url: [form.api_config_name, form.api_config_name.delete_suffix('/')])
|
67
|
+
|
68
|
+
if config
|
69
|
+
config.update!(deleted_at: nil)
|
70
|
+
|
71
|
+
form.api_config_name = config.name
|
72
|
+
else
|
73
|
+
form.api_config = Motor::ApiConfig.new(url: form.api_config_name.delete_suffix('/')).tap do |c|
|
74
|
+
c.name = c.url.sub(%r{\Ahttps?://}, '').delete_suffix('/')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
59
79
|
def archive_with_existing_name(form)
|
60
80
|
Motor::Form.where(['name = ? AND id != ?', form.name, form.id])
|
61
81
|
.update_all(deleted_at: Time.current)
|
data/lib/motor/net_http_utils.rb
CHANGED
@@ -4,7 +4,7 @@ module Motor
|
|
4
4
|
module NetHttpUtils
|
5
5
|
module_function
|
6
6
|
|
7
|
-
def get(url, params = {}, headers = {})
|
7
|
+
def get(url, params = {}, headers = {}, _body = nil)
|
8
8
|
request = build_request(Net::HTTP::Get, url, params, headers, nil)
|
9
9
|
|
10
10
|
execute_request(request)
|
@@ -16,9 +16,21 @@ module Motor
|
|
16
16
|
execute_request(request)
|
17
17
|
end
|
18
18
|
|
19
|
+
def put(url, params = {}, headers = {}, body = '')
|
20
|
+
request = build_request(Net::HTTP::Put, url, params, headers, body)
|
21
|
+
|
22
|
+
execute_request(request)
|
23
|
+
end
|
24
|
+
|
25
|
+
def delete(url, params = {}, headers = {}, body = '')
|
26
|
+
request = build_request(Net::HTTP::Delete, url, params, headers, body)
|
27
|
+
|
28
|
+
execute_request(request)
|
29
|
+
end
|
30
|
+
|
19
31
|
def build_request(method_class, url, params, headers, body)
|
20
32
|
uri = URI(url)
|
21
|
-
uri.query = params.to_query
|
33
|
+
uri.query = params.to_query if params.present?
|
22
34
|
|
23
35
|
request = method_class.new(uri)
|
24
36
|
request.body = body if body.present?
|
@@ -38,6 +38,7 @@ module Motor
|
|
38
38
|
|
39
39
|
ApplicationRecord.transaction do
|
40
40
|
archive_with_existing_name(query) if force_replace
|
41
|
+
assign_or_create_api_config!(query)
|
41
42
|
|
42
43
|
query.save!
|
43
44
|
end
|
@@ -61,6 +62,22 @@ module Motor
|
|
61
62
|
.update_all(deleted_at: Time.current)
|
62
63
|
end
|
63
64
|
|
65
|
+
def assign_or_create_api_config!(query)
|
66
|
+
api_config_name = query.preferences[:api_config_name]
|
67
|
+
|
68
|
+
return if api_config_name.blank?
|
69
|
+
return if Motor::ApiConfig.find_by(name: api_config_name)
|
70
|
+
|
71
|
+
config = Motor::ApiConfig.find_by(url: [api_config_name, api_config_name.delete_suffix('/')])
|
72
|
+
|
73
|
+
config&.update!(deleted_at: nil)
|
74
|
+
|
75
|
+
config ||= Motor::ApiConfig.create!(name: api_config_name.sub(%r{\Ahttps?://}, '').delete_suffix('/'),
|
76
|
+
url: api_config_name.delete_suffix('/'))
|
77
|
+
|
78
|
+
query.preferences[:api_config_name] = config.name
|
79
|
+
end
|
80
|
+
|
64
81
|
def name_already_exists?(query)
|
65
82
|
if query.new_record?
|
66
83
|
Query.exists?(name: query.name, deleted_at: nil)
|
data/lib/motor/version.rb
CHANGED
data/lib/motor.rb
CHANGED
Binary file
|
Binary file
|
data/ui/dist/manifest.json
CHANGED
@@ -2601,9 +2601,9 @@
|
|
2601
2601
|
"icons/zoom-out.svg.gz": "icons/zoom-out.svg.gz",
|
2602
2602
|
"icons/zoom-question.svg": "icons/zoom-question.svg",
|
2603
2603
|
"icons/zoom-question.svg.gz": "icons/zoom-question.svg.gz",
|
2604
|
-
"main-
|
2605
|
-
"main-
|
2606
|
-
"main-
|
2607
|
-
"main.css": "main-
|
2608
|
-
"main.js": "main-
|
2604
|
+
"main-90db17316da397cbfa9c.css.gz": "main-90db17316da397cbfa9c.css.gz",
|
2605
|
+
"main-90db17316da397cbfa9c.js.LICENSE.txt": "main-90db17316da397cbfa9c.js.LICENSE.txt",
|
2606
|
+
"main-90db17316da397cbfa9c.js.gz": "main-90db17316da397cbfa9c.js.gz",
|
2607
|
+
"main.css": "main-90db17316da397cbfa9c.css",
|
2608
|
+
"main.js": "main-90db17316da397cbfa9c.js"
|
2609
2609
|
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: motor-admin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.43
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pete Matsyburka
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-12-
|
11
|
+
date: 2021-12-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord-filter
|
@@ -114,6 +114,7 @@ files:
|
|
114
114
|
- app/controllers/motor/active_storage_attachments_controller.rb
|
115
115
|
- app/controllers/motor/alerts_controller.rb
|
116
116
|
- app/controllers/motor/api_base_controller.rb
|
117
|
+
- app/controllers/motor/api_configs_controller.rb
|
117
118
|
- app/controllers/motor/application_controller.rb
|
118
119
|
- app/controllers/motor/assets_controller.rb
|
119
120
|
- app/controllers/motor/audits_controller.rb
|
@@ -127,6 +128,7 @@ files:
|
|
127
128
|
- app/controllers/motor/resource_default_queries_controller.rb
|
128
129
|
- app/controllers/motor/resource_methods_controller.rb
|
129
130
|
- app/controllers/motor/resources_controller.rb
|
131
|
+
- app/controllers/motor/run_api_requests_controller.rb
|
130
132
|
- app/controllers/motor/run_queries_controller.rb
|
131
133
|
- app/controllers/motor/schema_controller.rb
|
132
134
|
- app/controllers/motor/send_alerts_controller.rb
|
@@ -139,6 +141,7 @@ files:
|
|
139
141
|
- app/mailers/motor/application_mailer.rb
|
140
142
|
- app/models/motor/alert.rb
|
141
143
|
- app/models/motor/alert_lock.rb
|
144
|
+
- app/models/motor/api_config.rb
|
142
145
|
- app/models/motor/application_record.rb
|
143
146
|
- app/models/motor/audit.rb
|
144
147
|
- app/models/motor/config.rb
|
@@ -158,6 +161,8 @@ files:
|
|
158
161
|
- lib/generators/motor/install_generator.rb
|
159
162
|
- lib/generators/motor/migration.rb
|
160
163
|
- lib/generators/motor/templates/install.rb
|
164
|
+
- lib/generators/motor/templates/install_api_configs.rb
|
165
|
+
- lib/generators/motor/upgrade_generator.rb
|
161
166
|
- lib/motor-admin.rb
|
162
167
|
- lib/motor.rb
|
163
168
|
- lib/motor/active_record_utils.rb
|
@@ -175,6 +180,7 @@ files:
|
|
175
180
|
- lib/motor/alerts/persistance.rb
|
176
181
|
- lib/motor/alerts/scheduled_alerts_cache.rb
|
177
182
|
- lib/motor/alerts/scheduler.rb
|
183
|
+
- lib/motor/api_configs.rb
|
178
184
|
- lib/motor/api_query.rb
|
179
185
|
- lib/motor/api_query/apply_scope.rb
|
180
186
|
- lib/motor/api_query/build_json.rb
|
@@ -1526,8 +1532,8 @@ files:
|
|
1526
1532
|
- ui/dist/icons/zoom-money.svg.gz
|
1527
1533
|
- ui/dist/icons/zoom-out.svg.gz
|
1528
1534
|
- ui/dist/icons/zoom-question.svg.gz
|
1529
|
-
- ui/dist/main-
|
1530
|
-
- ui/dist/main-
|
1535
|
+
- ui/dist/main-90db17316da397cbfa9c.css.gz
|
1536
|
+
- ui/dist/main-90db17316da397cbfa9c.js.gz
|
1531
1537
|
- ui/dist/manifest.json
|
1532
1538
|
homepage:
|
1533
1539
|
licenses:
|