motor-admin 0.1.35 → 0.1.41
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/concerns/motor/load_and_authorize_dynamic_resource.rb +70 -0
- data/app/controllers/motor/alerts_controller.rb +12 -6
- data/app/controllers/motor/audits_controller.rb +16 -0
- data/app/controllers/motor/configs_controller.rb +1 -0
- data/app/controllers/motor/dashboards_controller.rb +4 -0
- data/app/controllers/motor/data_controller.rb +2 -57
- data/app/controllers/motor/forms_controller.rb +4 -0
- data/app/controllers/motor/queries_controller.rb +4 -0
- data/app/controllers/motor/resources_controller.rb +1 -0
- data/app/controllers/motor/ui_controller.rb +4 -0
- data/app/models/motor/alert.rb +4 -2
- data/app/models/motor/application_record.rb +10 -0
- data/app/models/motor/audit.rb +9 -0
- data/app/models/motor/config.rb +2 -0
- data/app/models/motor/dashboard.rb +3 -1
- data/app/models/motor/form.rb +3 -1
- data/app/models/motor/query.rb +4 -1
- data/app/models/motor/resource.rb +2 -0
- data/app/views/motor/ui/show.html.erb +1 -1
- data/config/routes.rb +1 -0
- data/lib/generators/motor/templates/install.rb +40 -16
- data/lib/motor.rb +12 -3
- data/lib/motor/active_record_utils/defined_scopes_extension.rb +1 -1
- data/lib/motor/admin.rb +8 -0
- data/lib/motor/alerts/persistance.rb +17 -3
- data/lib/motor/alerts/scheduler.rb +1 -1
- data/lib/motor/api_query/apply_scope.rb +12 -5
- data/lib/motor/api_query/sort.rb +1 -1
- data/lib/motor/build_schema.rb +3 -3
- data/lib/motor/build_schema/find_display_column.rb +4 -4
- data/lib/motor/build_schema/load_from_rails.rb +20 -10
- data/lib/motor/build_schema/merge_schema_configs.rb +8 -4
- data/lib/motor/build_schema/reorder_schema.rb +10 -4
- data/lib/motor/configs.rb +17 -0
- data/lib/motor/configs/build_configs_hash.rb +83 -0
- data/lib/motor/configs/build_ui_app_tag.rb +71 -0
- data/lib/motor/configs/load_from_cache.rb +81 -0
- data/lib/motor/configs/sync_from_file.rb +36 -0
- data/lib/motor/configs/sync_from_hash.rb +126 -0
- data/lib/motor/configs/sync_middleware.rb +72 -0
- data/lib/motor/configs/sync_with_remote.rb +47 -0
- data/lib/motor/configs/write_to_file.rb +36 -0
- data/lib/motor/dashboards/persistance.rb +15 -5
- data/lib/motor/forms/persistance.rb +15 -5
- data/lib/motor/net_http_utils.rb +38 -0
- data/lib/motor/queries/persistance.rb +13 -3
- data/lib/motor/railtie.rb +11 -0
- data/lib/motor/tasks/motor.rake +37 -0
- data/lib/motor/version.rb +1 -1
- data/ui/dist/{main-03c3b1d3390877206e02.css.gz → main-0ef3be65da8d3b0dbabb.css.gz} +0 -0
- data/ui/dist/main-0ef3be65da8d3b0dbabb.js.gz +0 -0
- data/ui/dist/manifest.json +5 -5
- metadata +33 -5
- data/lib/motor/ui_configs.rb +0 -82
- data/ui/dist/main-03c3b1d3390877206e02.js.gz +0 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Motor
|
4
|
+
module Configs
|
5
|
+
FILE_PATH = 'config/motor.yml'
|
6
|
+
SYNC_API_PATH = '/motor_configs_sync'
|
7
|
+
SYNC_ACCESS_KEY = ENV.fetch('MOTOR_SYNC_API_KEY', '')
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
require_relative './configs/load_from_cache'
|
12
|
+
require_relative './configs/build_ui_app_tag'
|
13
|
+
require_relative './configs/build_configs_hash'
|
14
|
+
require_relative './configs/write_to_file'
|
15
|
+
require_relative './configs/sync_from_hash'
|
16
|
+
require_relative './configs/sync_from_file'
|
17
|
+
require_relative './configs/sync_with_remote'
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Motor
|
4
|
+
module Configs
|
5
|
+
module BuildConfigsHash
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def call
|
9
|
+
cache_keys = LoadFromCache.load_cache_keys
|
10
|
+
|
11
|
+
normalize_hash(
|
12
|
+
engine_version: Motor::VERSION,
|
13
|
+
file_version: cache_keys.values.compact.max.to_time,
|
14
|
+
resources: build_resources_hash(cache_keys[:resources]),
|
15
|
+
configs: build_configs_hash(cache_keys[:configs]),
|
16
|
+
queries: build_queries_hash(cache_keys[:queries]),
|
17
|
+
dashboards: build_dashboards_hash(cache_keys[:dashboards]),
|
18
|
+
forms: build_forms_hash(cache_keys[:forms]),
|
19
|
+
alerts: build_alerts_hash(cache_keys[:alerts])
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_queries_hash(cache_key = nil)
|
24
|
+
Motor::Configs::LoadFromCache.load_queries(cache_key: cache_key).sort_by(&:id).map do |query|
|
25
|
+
query.slice(%i[id name sql_body description preferences])
|
26
|
+
.merge(tags: query.tags.map(&:name), updated_at: query.updated_at.to_time)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_dashboards_hash(cache_key = nil)
|
31
|
+
Motor::Configs::LoadFromCache.load_dashboards(cache_key: cache_key).sort_by(&:id).map do |dashboard|
|
32
|
+
dashboard.slice(%i[id title description preferences])
|
33
|
+
.merge(tags: dashboard.tags.map(&:name), updated_at: dashboard.updated_at.to_time)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def build_alerts_hash(cache_key = nil)
|
38
|
+
Motor::Configs::LoadFromCache.load_alerts(cache_key: cache_key).sort_by(&:id).map do |alert|
|
39
|
+
alert.slice(%i[id name query_id to_emails is_enabled description preferences])
|
40
|
+
.merge(tags: alert.tags.map(&:name), updated_at: alert.updated_at.to_time)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def build_forms_hash(cache_key = nil)
|
45
|
+
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])
|
47
|
+
.merge(tags: form.tags.map(&:name), updated_at: form.updated_at.to_time)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def build_configs_hash(cache_key = nil)
|
52
|
+
Motor::Configs::LoadFromCache.load_configs(cache_key: cache_key).sort_by(&:key).map do |config|
|
53
|
+
{
|
54
|
+
key: config.key,
|
55
|
+
value: config.value,
|
56
|
+
updated_at: config.updated_at.to_time
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def build_resources_hash(cache_key = nil)
|
62
|
+
Motor::Configs::LoadFromCache.load_resources(cache_key: cache_key).sort_by(&:name).map do |resource|
|
63
|
+
{
|
64
|
+
name: resource.name,
|
65
|
+
preferences: resource.preferences,
|
66
|
+
updated_at: resource.updated_at.to_time
|
67
|
+
}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def normalize_hash(value)
|
72
|
+
case value
|
73
|
+
when Hash, HashWithIndifferentAccess
|
74
|
+
value.to_h.stringify_keys.transform_values { |v| normalize_hash(v) }
|
75
|
+
when Array
|
76
|
+
value.map { |e| normalize_hash(e) }
|
77
|
+
else
|
78
|
+
value
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Motor
|
4
|
+
module Configs
|
5
|
+
module BuildUiAppTag
|
6
|
+
CACHE_STORE =
|
7
|
+
if Motor.development?
|
8
|
+
ActiveSupport::Cache::NullStore.new
|
9
|
+
else
|
10
|
+
ActiveSupport::Cache::MemoryStore.new(size: 5.megabytes)
|
11
|
+
end
|
12
|
+
|
13
|
+
module_function
|
14
|
+
|
15
|
+
def call
|
16
|
+
cache_keys = LoadFromCache.load_cache_keys
|
17
|
+
|
18
|
+
CACHE_STORE.fetch(cache_keys.hash) do
|
19
|
+
CACHE_STORE.clear
|
20
|
+
|
21
|
+
Motor::ApplicationController.helpers.content_tag(
|
22
|
+
:div, '', id: 'app', data: build_data(cache_keys)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [Hash]
|
28
|
+
def build_data(cache_keys = {})
|
29
|
+
{
|
30
|
+
base_path: Motor::Admin.routes.url_helpers.motor_path,
|
31
|
+
schema: Motor::BuildSchema.call(cache_keys),
|
32
|
+
header_links: header_links_data_hash(cache_keys[:configs]),
|
33
|
+
queries: queries_data_hash(cache_keys[:queries]),
|
34
|
+
dashboards: dashboards_data_hash(cache_keys[:dashboards]),
|
35
|
+
alerts: alerts_data_hash(cache_keys[:alerts]),
|
36
|
+
forms: forms_data_hash(cache_keys[:forms])
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def header_links_data_hash(cache_key = nil)
|
41
|
+
configs = Motor::Configs::LoadFromCache.load_configs(cache_key: cache_key)
|
42
|
+
|
43
|
+
configs.find { |c| c.key == 'header.links' }&.value || []
|
44
|
+
end
|
45
|
+
|
46
|
+
def queries_data_hash(cache_key = nil)
|
47
|
+
Motor::Configs::LoadFromCache.load_queries(cache_key: cache_key)
|
48
|
+
.as_json(only: %i[id name updated_at],
|
49
|
+
include: { tags: { only: %i[id name] } })
|
50
|
+
end
|
51
|
+
|
52
|
+
def dashboards_data_hash(cache_key = nil)
|
53
|
+
Motor::Configs::LoadFromCache.load_dashboards(cache_key: cache_key)
|
54
|
+
.as_json(only: %i[id title updated_at],
|
55
|
+
include: { tags: { only: %i[id name] } })
|
56
|
+
end
|
57
|
+
|
58
|
+
def alerts_data_hash(cache_key = nil)
|
59
|
+
Motor::Configs::LoadFromCache.load_alerts(cache_key: cache_key)
|
60
|
+
.as_json(only: %i[id name is_enabled updated_at],
|
61
|
+
include: { tags: { only: %i[id name] } })
|
62
|
+
end
|
63
|
+
|
64
|
+
def forms_data_hash(cache_key = nil)
|
65
|
+
Motor::Configs::LoadFromCache.load_forms(cache_key: cache_key)
|
66
|
+
.as_json(only: %i[id name updated_at],
|
67
|
+
include: { tags: { only: %i[id name] } })
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Motor
|
4
|
+
module Configs
|
5
|
+
module LoadFromCache
|
6
|
+
CACHE_STORE = ActiveSupport::Cache::MemoryStore.new(size: 10.megabytes)
|
7
|
+
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def call
|
11
|
+
cache_keys = load_cache_keys
|
12
|
+
|
13
|
+
{
|
14
|
+
configs: load_configs(cache_key: cache_keys[:configs]),
|
15
|
+
resources: load_resources(cache_key: cache_keys[:resources]),
|
16
|
+
queries: load_queries(cache_key: cache_keys[:queries]),
|
17
|
+
dashboards: load_dashboards(cache_key: cache_keys[:dashboards]),
|
18
|
+
alerts: load_alerts(cache_key: cache_keys[:alerts]),
|
19
|
+
forms: load_forms(cache_key: cache_keys[:forms])
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def load_configs(cache_key: nil)
|
24
|
+
maybe_fetch_from_cache('configs', cache_key) do
|
25
|
+
Motor::Config.all.load
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def load_resources(cache_key: nil)
|
30
|
+
maybe_fetch_from_cache('resources', cache_key) do
|
31
|
+
Motor::Resource.all.load
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def load_queries(cache_key: nil)
|
36
|
+
maybe_fetch_from_cache('queries', cache_key) do
|
37
|
+
Motor::Query.all.active.preload(:tags).load
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def load_dashboards(cache_key: nil)
|
42
|
+
maybe_fetch_from_cache('dashboards', cache_key) do
|
43
|
+
Motor::Dashboard.all.active.preload(:tags).load
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def load_alerts(cache_key: nil)
|
48
|
+
maybe_fetch_from_cache('alerts', cache_key) do
|
49
|
+
Motor::Alert.all.active.preload(:tags).load
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def load_forms(cache_key: nil)
|
54
|
+
maybe_fetch_from_cache('forms', cache_key) do
|
55
|
+
Motor::Form.all.active.preload(:tags).load
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def maybe_fetch_from_cache(type, cache_key, &block)
|
60
|
+
return block.call unless cache_key
|
61
|
+
|
62
|
+
CACHE_STORE.fetch(type + cache_key.to_s, &block)
|
63
|
+
end
|
64
|
+
|
65
|
+
def load_cache_keys
|
66
|
+
ActiveRecord::Base.connection.execute(
|
67
|
+
"(#{
|
68
|
+
[
|
69
|
+
Motor::Config.select("'configs', MAX(updated_at)").to_sql,
|
70
|
+
Motor::Resource.select("'resources', MAX(updated_at)").to_sql,
|
71
|
+
Motor::Dashboard.select("'dashboards', MAX(updated_at)").to_sql,
|
72
|
+
Motor::Alert.select("'alerts', MAX(updated_at)").to_sql,
|
73
|
+
Motor::Query.select("'queries', MAX(updated_at)").to_sql,
|
74
|
+
Motor::Form.select("'forms', MAX(updated_at)").to_sql
|
75
|
+
].join(') UNION (')
|
76
|
+
})"
|
77
|
+
).to_a.map(&:values).to_h.with_indifferent_access
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Motor
|
4
|
+
module Configs
|
5
|
+
module SyncFromFile
|
6
|
+
FILE_PATH = Motor::Configs::FILE_PATH
|
7
|
+
MUTEXT = Mutex.new
|
8
|
+
FILE_TIMESTAMPS_STORE = ActiveSupport::Cache::MemoryStore.new(size: 1.megabyte)
|
9
|
+
|
10
|
+
module_function
|
11
|
+
|
12
|
+
def call(with_exception: false)
|
13
|
+
MUTEXT.synchronize do
|
14
|
+
file = Rails.root.join(FILE_PATH)
|
15
|
+
|
16
|
+
file_timestamp =
|
17
|
+
begin
|
18
|
+
file.ctime
|
19
|
+
rescue Errno::ENOENT
|
20
|
+
raise if with_exception
|
21
|
+
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
next unless file_timestamp
|
26
|
+
|
27
|
+
FILE_TIMESTAMPS_STORE.fetch(file_timestamp.to_s) do
|
28
|
+
Motor::Configs::SyncFromHash.call(
|
29
|
+
YAML.safe_load(file.read, permitted_classes: [Time, Date])
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Motor
|
4
|
+
module Configs
|
5
|
+
module SyncFromHash
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def call(configs_hash)
|
9
|
+
return if configs_hash.blank?
|
10
|
+
|
11
|
+
configs_hash = configs_hash.with_indifferent_access
|
12
|
+
|
13
|
+
Motor::ApplicationRecord.transaction do
|
14
|
+
sync_queries(configs_hash)
|
15
|
+
sync_alerts(configs_hash)
|
16
|
+
sync_dashboards(configs_hash)
|
17
|
+
sync_forms(configs_hash)
|
18
|
+
sync_configs(configs_hash)
|
19
|
+
sync_resources(configs_hash)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def sync_queries(configs_hash)
|
24
|
+
sync_taggable(
|
25
|
+
Motor::Configs::LoadFromCache.load_queries,
|
26
|
+
configs_hash[:queries],
|
27
|
+
configs_hash[:file_version],
|
28
|
+
Motor::Queries::Persistance.method(:update_from_params!)
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def sync_alerts(configs_hash)
|
33
|
+
sync_taggable(
|
34
|
+
Motor::Configs::LoadFromCache.load_alerts,
|
35
|
+
configs_hash[:alerts],
|
36
|
+
configs_hash[:file_version],
|
37
|
+
Motor::Alerts::Persistance.method(:update_from_params!)
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def sync_forms(configs_hash)
|
42
|
+
sync_taggable(
|
43
|
+
Motor::Configs::LoadFromCache.load_forms,
|
44
|
+
configs_hash[:forms],
|
45
|
+
configs_hash[:file_version],
|
46
|
+
Motor::Forms::Persistance.method(:update_from_params!)
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def sync_dashboards(configs_hash)
|
51
|
+
sync_taggable(
|
52
|
+
Motor::Configs::LoadFromCache.load_dashboards,
|
53
|
+
configs_hash[:dashboards],
|
54
|
+
configs_hash[:file_version],
|
55
|
+
Motor::Dashboards::Persistance.method(:update_from_params!)
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def sync_configs(configs_hash)
|
60
|
+
configs_index = Motor::Configs::LoadFromCache.load_configs.index_by(&:key)
|
61
|
+
|
62
|
+
configs_hash[:configs].each do |attrs|
|
63
|
+
record = configs_index[attrs[:key]] || Motor::Config.new
|
64
|
+
|
65
|
+
next if record.updated_at && attrs[:updated_at] <= record.updated_at
|
66
|
+
|
67
|
+
record.update!(attrs)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def sync_resources(configs_hash)
|
72
|
+
resources_index = Motor::Configs::LoadFromCache.load_resources.index_by(&:name)
|
73
|
+
|
74
|
+
configs_hash[:resources].each do |attrs|
|
75
|
+
record = resources_index[attrs[:name]] || Motor::Resource.new
|
76
|
+
|
77
|
+
next if record.updated_at && attrs[:updated_at] <= record.updated_at
|
78
|
+
|
79
|
+
record.update!(attrs)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def sync_taggable(records, config_items, configs_timestamp, update_proc)
|
84
|
+
processed_records, create_items = update_taggable_items(records, config_items, update_proc)
|
85
|
+
|
86
|
+
create_taggable_items(create_items, records.klass, update_proc)
|
87
|
+
|
88
|
+
archive_taggable_items(records - processed_records, configs_timestamp)
|
89
|
+
|
90
|
+
ActiveRecord::Base.connection.reset_pk_sequence!(records.klass.table_name)
|
91
|
+
end
|
92
|
+
|
93
|
+
def update_taggable_items(records, config_items, update_proc)
|
94
|
+
record_ids_hash = records.index_by(&:id)
|
95
|
+
|
96
|
+
config_items.each_with_object([[], []]) do |attrs, (processed_acc, create_acc)|
|
97
|
+
record = record_ids_hash[attrs[:id]]
|
98
|
+
|
99
|
+
next create_acc << attrs unless record
|
100
|
+
|
101
|
+
processed_acc << record if record
|
102
|
+
|
103
|
+
next if record.updated_at >= attrs[:updated_at]
|
104
|
+
|
105
|
+
update_proc.call(record, attrs, force_replace: true)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def create_taggable_items(create_items, records_class, update_proc)
|
110
|
+
create_items.each do |attrs|
|
111
|
+
record = records_class.find_or_initialize_by(id: attrs[:id]).tap { |e| e.deleted_at = nil }
|
112
|
+
|
113
|
+
update_proc.call(record, attrs, force_replace: true)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def archive_taggable_items(records_to_remove, configs_timestamp)
|
118
|
+
records_to_remove.each do |record|
|
119
|
+
next if record.updated_at > configs_timestamp
|
120
|
+
|
121
|
+
record.update!(deleted_at: Time.current) if record.deleted_at.blank?
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Motor
|
4
|
+
module Configs
|
5
|
+
class SyncMiddleware
|
6
|
+
KeyNotSpecified = Class.new(StandardError)
|
7
|
+
NotAuthenticated = Class.new(StandardError)
|
8
|
+
|
9
|
+
def initialize(app)
|
10
|
+
@app = app
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
if env['PATH_INFO'] == Motor::Configs::SYNC_API_PATH
|
15
|
+
authenticate!(env['HTTP_X_AUTHORIZATION'])
|
16
|
+
|
17
|
+
case env['REQUEST_METHOD']
|
18
|
+
when 'GET'
|
19
|
+
respond_with_configs
|
20
|
+
when 'POST'
|
21
|
+
input = env['rack.input']
|
22
|
+
input.rewind
|
23
|
+
sync_configs(input.read)
|
24
|
+
else
|
25
|
+
@app.call(env)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
@app.call(env)
|
29
|
+
end
|
30
|
+
rescue NotAuthenticated
|
31
|
+
[403, {}, ['Invalid synchronization API key']]
|
32
|
+
rescue KeyNotSpecified
|
33
|
+
[404, {}, ['Set `MOTOR_SYNC_API_KEY` environment variable in order to sync configs']]
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def authenticate!(token)
|
39
|
+
raise KeyNotSpecified if Motor::Configs::SYNC_ACCESS_KEY.blank?
|
40
|
+
raise NotAuthenticated if token.blank?
|
41
|
+
|
42
|
+
is_token_valid =
|
43
|
+
ActiveSupport::SecurityUtils.secure_compare(
|
44
|
+
Digest::SHA256.hexdigest(token),
|
45
|
+
Digest::SHA256.hexdigest(Motor::Configs::SYNC_ACCESS_KEY)
|
46
|
+
)
|
47
|
+
|
48
|
+
raise NotAuthenticated unless is_token_valid
|
49
|
+
end
|
50
|
+
|
51
|
+
def respond_with_configs
|
52
|
+
[
|
53
|
+
200,
|
54
|
+
{ 'Content-Type' => 'application/json' },
|
55
|
+
[Motor::Configs::BuildConfigsHash.call.to_json]
|
56
|
+
]
|
57
|
+
rescue StandardError => e
|
58
|
+
[500, {}, [e.message]]
|
59
|
+
end
|
60
|
+
|
61
|
+
def sync_configs(body)
|
62
|
+
configs_hash = JSON.parse(body)
|
63
|
+
|
64
|
+
Motor::Configs::SyncFromHash.call(configs_hash)
|
65
|
+
|
66
|
+
[200, {}, []]
|
67
|
+
rescue StandardError => e
|
68
|
+
[500, {}, [e.message]]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|