motor-admin 0.1.46 → 0.1.51
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/LICENSE +1 -1
- data/README.md +129 -9
- data/app/controllers/concerns/motor/current_user_method.rb +15 -0
- data/app/controllers/motor/api_base_controller.rb +11 -17
- data/app/controllers/motor/application_controller.rb +1 -0
- data/app/controllers/motor/assets_controller.rb +2 -2
- data/app/controllers/motor/icons_controller.rb +1 -1
- data/app/controllers/motor/ui_controller.rb +12 -4
- data/app/mailers/motor/alerts_mailer.rb +5 -5
- data/app/models/motor/alert.rb +1 -0
- data/app/models/motor/dashboard.rb +1 -0
- data/app/models/motor/form.rb +1 -0
- data/app/models/motor/query.rb +1 -0
- data/app/models/motor/resource.rb +1 -0
- data/app/models/motor/tag.rb +1 -1
- data/app/views/motor/alerts_mailer/alert_email.html.erb +1 -1
- data/app/views/motor/ui/show.html.erb +1 -1
- data/config/routes.rb +8 -9
- data/lib/generators/motor/templates/install.rb +74 -65
- data/lib/motor.rb +0 -1
- data/lib/motor/active_record_utils.rb +13 -1
- data/lib/motor/admin.rb +1 -1
- data/lib/motor/alerts/persistance.rb +4 -4
- data/lib/motor/alerts/scheduled_alerts_cache.rb +2 -1
- data/lib/motor/alerts/scheduler.rb +1 -1
- data/lib/motor/api_query/apply_scope.rb +1 -1
- data/lib/motor/api_query/build_json.rb +6 -6
- data/lib/motor/api_query/paginate.rb +1 -0
- data/lib/motor/api_query/search.rb +1 -7
- data/lib/motor/assets.rb +1 -1
- data/lib/motor/build_schema/find_display_column.rb +1 -0
- data/lib/motor/build_schema/find_icon.rb +9 -7
- data/lib/motor/build_schema/load_from_rails.rb +5 -2
- data/lib/motor/configs/build_ui_app_tag.rb +8 -7
- data/lib/motor/configs/load_from_cache.rb +19 -14
- data/lib/motor/configs/sync_from_hash.rb +1 -1
- data/lib/motor/configs/sync_with_remote.rb +1 -1
- data/lib/motor/configs/write_to_file.rb +1 -0
- data/lib/motor/dashboards/persistance.rb +4 -4
- data/lib/motor/forms/persistance.rb +4 -4
- data/lib/motor/queries/persistance.rb +4 -4
- data/lib/motor/queries/run_query.rb +3 -3
- data/lib/motor/tags.rb +2 -2
- data/lib/motor/tasks/motor.rake +4 -0
- data/lib/motor/version.rb +1 -1
- data/ui/dist/{main-c0cfd92d021794d8cf13.css.gz → main-36a9ee6a9b0427a77d87.css.gz} +0 -0
- data/ui/dist/main-36a9ee6a9b0427a77d87.js.gz +0 -0
- data/ui/dist/manifest.json +5 -5
- metadata +5 -4
- data/ui/dist/main-c0cfd92d021794d8cf13.js.gz +0 -0
data/lib/motor.rb
CHANGED
@@ -40,7 +40,6 @@ module Motor
|
|
40
40
|
(defined?(::Puma) && File.basename($PROGRAM_NAME) == 'puma') ||
|
41
41
|
defined?(::Unicorn::HttpServer) ||
|
42
42
|
defined?(::Mongrel::HttpServer) ||
|
43
|
-
defined?(::WEBrick::VERSION) ||
|
44
43
|
defined?(JRuby::Rack::VERSION) ||
|
45
44
|
defined?(::Trinidad::Server)
|
46
45
|
end
|
@@ -1,6 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module
|
3
|
+
module Motor
|
4
|
+
module ActiveRecordUtils
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def reset_id_sequence!(model)
|
8
|
+
case ActiveRecord::Base.connection.class.name
|
9
|
+
when 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter'
|
10
|
+
ActiveRecord::Base.connection.reset_pk_sequence!(model.table_name)
|
11
|
+
else
|
12
|
+
ActiveRecord::Base.connection.reset_sequence!(model.table_name, 'id')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
4
16
|
end
|
5
17
|
|
6
18
|
require_relative './active_record_utils/types'
|
data/lib/motor/admin.rb
CHANGED
@@ -28,7 +28,7 @@ module Motor
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def create_from_params!(params, current_user = nil)
|
31
|
-
raise NameAlreadyExists if Alert.exists?(
|
31
|
+
raise NameAlreadyExists if Alert.exists?(name: params[:name])
|
32
32
|
|
33
33
|
alert = build_from_params(params, current_user)
|
34
34
|
|
@@ -77,7 +77,7 @@ module Motor
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def archive_with_existing_name(alert)
|
80
|
-
Motor::Alert.where(['
|
80
|
+
Motor::Alert.where(['name = ? AND id != ?', alert.name, alert.id])
|
81
81
|
.update_all(deleted_at: Time.current)
|
82
82
|
end
|
83
83
|
|
@@ -87,9 +87,9 @@ module Motor
|
|
87
87
|
|
88
88
|
def name_already_exists?(alert)
|
89
89
|
if alert.new_record?
|
90
|
-
Alert.exists?(
|
90
|
+
Alert.exists?(name: alert.name)
|
91
91
|
else
|
92
|
-
Alert.exists?(['
|
92
|
+
Alert.exists?(['name = ? AND id != ?', alert.name, alert.id])
|
93
93
|
end
|
94
94
|
end
|
95
95
|
end
|
@@ -3,7 +3,8 @@
|
|
3
3
|
module Motor
|
4
4
|
module Alerts
|
5
5
|
module ScheduledAlertsCache
|
6
|
-
CACHE_STORE = ActiveSupport::Cache::MemoryStore.new(size: 5.megabytes
|
6
|
+
CACHE_STORE = ActiveSupport::Cache::MemoryStore.new(size: 5.megabytes,
|
7
|
+
coder: ActiveSupport::Cache::NullCoder)
|
7
8
|
|
8
9
|
module_function
|
9
10
|
|
@@ -10,12 +10,12 @@ module Motor
|
|
10
10
|
|
11
11
|
rel = rel.preload_associations_lazily if rel.is_a?(ActiveRecord::Relation)
|
12
12
|
|
13
|
-
json_params = {}
|
13
|
+
json_params = {}.with_indifferent_access
|
14
14
|
|
15
15
|
assign_include_params(json_params, rel, params)
|
16
16
|
assign_fields_params(json_params, rel, params)
|
17
17
|
|
18
|
-
rel.as_json(json_params
|
18
|
+
rel.as_json(json_params)
|
19
19
|
end
|
20
20
|
|
21
21
|
def assign_include_params(json_params, _rel, api_params)
|
@@ -51,11 +51,11 @@ module Motor
|
|
51
51
|
params[:fields].each do |key, fields|
|
52
52
|
fields = fields.split(',') if fields.is_a?(String)
|
53
53
|
|
54
|
-
merge_fields_params!(key, fields,
|
54
|
+
merge_fields_params!(json_params, key, fields, model)
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
def merge_fields_params!(key, fields,
|
58
|
+
def merge_fields_params!(json_params, key, fields, model)
|
59
59
|
model_name = model.name.underscore
|
60
60
|
|
61
61
|
if key == model_name || model_name.split('/').last == key
|
@@ -96,8 +96,8 @@ module Motor
|
|
96
96
|
def normalize_include_params(params)
|
97
97
|
case params
|
98
98
|
when Array
|
99
|
-
params.
|
100
|
-
|
99
|
+
params.index_with do |_|
|
100
|
+
{ 'include' => {} }
|
101
101
|
end
|
102
102
|
when String
|
103
103
|
{ params => { 'include' => {} } }
|
@@ -57,13 +57,7 @@ module Motor
|
|
57
57
|
def find_searchable_columns(model)
|
58
58
|
model.columns.map do |column|
|
59
59
|
next unless column.type.in?(COLUMN_TYPES)
|
60
|
-
|
61
|
-
has_inclusion_validator =
|
62
|
-
model.validators_on(column.name).any? do |e|
|
63
|
-
e.is_a?(ActiveModel::Validations::InclusionValidator)
|
64
|
-
end
|
65
|
-
|
66
|
-
next if has_inclusion_validator
|
60
|
+
next if model.validators_on(column.name).any?(ActiveModel::Validations::InclusionValidator)
|
67
61
|
|
68
62
|
column.name
|
69
63
|
end.compact
|
data/lib/motor/assets.rb
CHANGED
@@ -3,10 +3,17 @@
|
|
3
3
|
module Motor
|
4
4
|
module FindIcon
|
5
5
|
ICONS_MAP = {
|
6
|
+
'audit' => 'history',
|
7
|
+
'block' => 'ban',
|
8
|
+
'blocked' => 'ban',
|
9
|
+
'blacklisted' => 'ban',
|
10
|
+
'blocklisted' => 'ban',
|
11
|
+
'banned' => 'ban',
|
6
12
|
'website' => 'world',
|
7
13
|
'location' => 'gps',
|
8
14
|
'photo' => 'photo',
|
9
15
|
'image' => 'photo',
|
16
|
+
'screenshot' => 'photo',
|
10
17
|
'picture' => 'photo',
|
11
18
|
'video' => 'video',
|
12
19
|
'file' => 'file',
|
@@ -28,7 +35,6 @@ module Motor
|
|
28
35
|
'token' => 'key',
|
29
36
|
'secret' => 'lock',
|
30
37
|
'automation' => 'manual-gearbox',
|
31
|
-
'email' => 'mail',
|
32
38
|
'relationship' => 'hierarchy',
|
33
39
|
'person' => 'user',
|
34
40
|
'people' => 'users',
|
@@ -43,7 +49,6 @@ module Motor
|
|
43
49
|
'rule' => 'manual-gearbox',
|
44
50
|
'tracking' => 'zoom-question',
|
45
51
|
'github' => 'brand-github',
|
46
|
-
'block' => 'ban',
|
47
52
|
'tag' => 'hash',
|
48
53
|
'category' => 'hash',
|
49
54
|
'label' => 'hash',
|
@@ -60,15 +65,11 @@ module Motor
|
|
60
65
|
'model' => 'hash',
|
61
66
|
'taxon' => 'hash',
|
62
67
|
'affiliate' => 'affiliate',
|
63
|
-
'blocked' => 'ban',
|
64
|
-
'blacklisted' => 'ban',
|
65
|
-
'blocklisted' => 'ban',
|
66
68
|
'chat' => 'message-circle',
|
67
69
|
'message' => 'messages',
|
68
70
|
'poll' => 'messages',
|
69
71
|
'feedpack' => 'messages',
|
70
72
|
'attachment' => 'paperclip',
|
71
|
-
'banned' => 'ban',
|
72
73
|
'certificate' => 'certificate',
|
73
74
|
'approval' => 'certificate',
|
74
75
|
'bank' => 'building-bank',
|
@@ -105,7 +106,8 @@ module Motor
|
|
105
106
|
'subscriber' => 'user-plus',
|
106
107
|
'product' => 'building-store',
|
107
108
|
'html' => 'code',
|
108
|
-
'stripe' => 'brand-stripe'
|
109
|
+
'stripe' => 'brand-stripe',
|
110
|
+
'email' => 'mail'
|
109
111
|
}.freeze
|
110
112
|
|
111
113
|
DEFAULT_ICON = 'database'
|
@@ -12,6 +12,8 @@ module Motor
|
|
12
12
|
models.map do |model|
|
13
13
|
Object.const_get(model.name)
|
14
14
|
|
15
|
+
next unless ActiveRecord::Base.connection.table_exists?(model.table_name)
|
16
|
+
|
15
17
|
schema = build_model_schema(model)
|
16
18
|
|
17
19
|
if model.respond_to?(:devise_modules)
|
@@ -20,7 +22,7 @@ module Motor
|
|
20
22
|
|
21
23
|
schema
|
22
24
|
rescue StandardError, NotImplementedError => e
|
23
|
-
Rails.logger.error(e)
|
25
|
+
Rails.logger.error(e)
|
24
26
|
|
25
27
|
next
|
26
28
|
end.compact
|
@@ -34,6 +36,7 @@ module Motor
|
|
34
36
|
models -= Motor::ApplicationRecord.descendants
|
35
37
|
models -= [Motor::Audit]
|
36
38
|
models -= [ActiveRecord::SchemaMigration] if defined?(ActiveRecord::SchemaMigration)
|
39
|
+
models -= [ActiveRecord::InternalMetadata] if defined?(ActiveRecord::InternalMetadata)
|
37
40
|
models -= [ActiveStorage::Blob] if defined?(ActiveStorage::Blob)
|
38
41
|
models -= [ActiveStorage::VariantRecord] if defined?(ActiveStorage::VariantRecord)
|
39
42
|
|
@@ -101,7 +104,7 @@ module Motor
|
|
101
104
|
name: column.name,
|
102
105
|
display_name: Utils.humanize_column_name(column.name),
|
103
106
|
column_type: is_enum ? 'string' : UNIFIED_TYPES[column.type.to_s] || column.type.to_s,
|
104
|
-
is_array: column.array?,
|
107
|
+
is_array: column.respond_to?(:array?) && column.array?,
|
105
108
|
access_type: COLUMN_NAME_ACCESS_TYPES.fetch(column.name, ColumnAccessTypes::READ_WRITE),
|
106
109
|
default_value: default_attrs[column.name],
|
107
110
|
validators: fetch_validators(model, column.name),
|
@@ -7,26 +7,27 @@ module Motor
|
|
7
7
|
if Motor.development?
|
8
8
|
ActiveSupport::Cache::NullStore.new
|
9
9
|
else
|
10
|
-
ActiveSupport::Cache::MemoryStore.new(size: 5.megabytes
|
10
|
+
ActiveSupport::Cache::MemoryStore.new(size: 5.megabytes,
|
11
|
+
coder: ActiveSupport::Cache::NullCoder)
|
11
12
|
end
|
12
13
|
|
13
14
|
module_function
|
14
15
|
|
15
|
-
def call
|
16
|
+
def call(current_user = nil)
|
16
17
|
cache_keys = LoadFromCache.load_cache_keys
|
17
18
|
|
18
|
-
CACHE_STORE.fetch(cache_keys.hash) do
|
19
|
+
CACHE_STORE.fetch("#{cache_keys.hash}#{current_user&.id}") do
|
19
20
|
CACHE_STORE.clear
|
20
21
|
|
21
|
-
Motor::ApplicationController.helpers.
|
22
|
-
:div, '', id: 'app', data: build_data(cache_keys)
|
23
|
-
)
|
22
|
+
Motor::ApplicationController.helpers.tag.div('', id: 'app', data: build_data(cache_keys, current_user))
|
24
23
|
end
|
25
24
|
end
|
26
25
|
|
27
26
|
# @return [Hash]
|
28
|
-
def build_data(cache_keys = {})
|
27
|
+
def build_data(cache_keys = {}, current_user = nil)
|
29
28
|
{
|
29
|
+
current_user: current_user&.as_json(only: %i[id email]),
|
30
|
+
audits_count: Motor::Audit.count,
|
30
31
|
base_path: Motor::Admin.routes.url_helpers.motor_path,
|
31
32
|
schema: Motor::BuildSchema.call(cache_keys),
|
32
33
|
header_links: header_links_data_hash(cache_keys[:configs]),
|
@@ -3,7 +3,8 @@
|
|
3
3
|
module Motor
|
4
4
|
module Configs
|
5
5
|
module LoadFromCache
|
6
|
-
CACHE_STORE = ActiveSupport::Cache::MemoryStore.new(size: 10.megabytes
|
6
|
+
CACHE_STORE = ActiveSupport::Cache::MemoryStore.new(size: 10.megabytes,
|
7
|
+
coder: ActiveSupport::Cache::NullCoder)
|
7
8
|
|
8
9
|
module_function
|
9
10
|
|
@@ -57,24 +58,28 @@ module Motor
|
|
57
58
|
end
|
58
59
|
|
59
60
|
def maybe_fetch_from_cache(type, cache_key, &block)
|
60
|
-
return
|
61
|
+
return yield unless cache_key
|
61
62
|
|
62
63
|
CACHE_STORE.fetch(type + cache_key.to_s, &block)
|
63
64
|
end
|
64
65
|
|
65
66
|
def load_cache_keys
|
66
|
-
ActiveRecord::Base.connection.execute(
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
67
|
+
result = ActiveRecord::Base.connection.execute(cache_keys_sql).to_a
|
68
|
+
|
69
|
+
result = result.map(&:values) if result.first.is_a?(Hash)
|
70
|
+
|
71
|
+
result.to_h.with_indifferent_access
|
72
|
+
end
|
73
|
+
|
74
|
+
def cache_keys_sql
|
75
|
+
[
|
76
|
+
Motor::Config.select("'configs', MAX(updated_at)").to_sql,
|
77
|
+
Motor::Resource.select("'resources', MAX(updated_at)").to_sql,
|
78
|
+
Motor::Dashboard.select("'dashboards', MAX(updated_at)").to_sql,
|
79
|
+
Motor::Alert.select("'alerts', MAX(updated_at)").to_sql,
|
80
|
+
Motor::Query.select("'queries', MAX(updated_at)").to_sql,
|
81
|
+
Motor::Form.select("'forms', MAX(updated_at)").to_sql
|
82
|
+
].join(' UNION ')
|
78
83
|
end
|
79
84
|
end
|
80
85
|
end
|
@@ -87,7 +87,7 @@ module Motor
|
|
87
87
|
|
88
88
|
archive_taggable_items(records - processed_records, configs_timestamp)
|
89
89
|
|
90
|
-
|
90
|
+
ActiveRecordUtils.reset_id_sequence!(records.klass)
|
91
91
|
end
|
92
92
|
|
93
93
|
def update_taggable_items(records, config_items, update_proc)
|
@@ -9,7 +9,7 @@ module Motor
|
|
9
9
|
module_function
|
10
10
|
|
11
11
|
def call(remote_url, api_key)
|
12
|
-
url = remote_url.
|
12
|
+
url = remote_url.delete_suffix('/') + Motor::Configs::SYNC_API_PATH
|
13
13
|
|
14
14
|
sync_from_remote!(url, api_key)
|
15
15
|
sync_to_remote!(url, api_key)
|
@@ -16,7 +16,7 @@ module Motor
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def create_from_params!(params, current_user = nil)
|
19
|
-
raise TitleAlreadyExists if Dashboard.exists?(
|
19
|
+
raise TitleAlreadyExists if Dashboard.exists?(title: params[:title])
|
20
20
|
|
21
21
|
dashboard = build_from_params(params, current_user)
|
22
22
|
|
@@ -57,15 +57,15 @@ module Motor
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def archive_with_existing_name(dashboard)
|
60
|
-
Motor::Dashboard.where(['
|
60
|
+
Motor::Dashboard.where(['title = ? AND id != ?', dashboard.title, dashboard.id])
|
61
61
|
.update_all(deleted_at: Time.current)
|
62
62
|
end
|
63
63
|
|
64
64
|
def title_already_exists?(dashboard)
|
65
65
|
if dashboard.new_record?
|
66
|
-
Motor::Dashboard.exists?(
|
66
|
+
Motor::Dashboard.exists?(title: dashboard.title)
|
67
67
|
else
|
68
|
-
Motor::Dashboard.exists?(['
|
68
|
+
Motor::Dashboard.exists?(['title = ? AND id != ?', dashboard.title, dashboard.id])
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
@@ -16,7 +16,7 @@ module Motor
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def create_from_params!(params, current_user = nil)
|
19
|
-
raise NameAlreadyExists if Form.exists?(
|
19
|
+
raise NameAlreadyExists if Form.exists?(name: params[:name])
|
20
20
|
|
21
21
|
form = build_from_params(params, current_user)
|
22
22
|
|
@@ -57,15 +57,15 @@ module Motor
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def archive_with_existing_name(form)
|
60
|
-
Motor::Form.where(['
|
60
|
+
Motor::Form.where(['name = ? AND id != ?', form.name, form.id])
|
61
61
|
.update_all(deleted_at: Time.current)
|
62
62
|
end
|
63
63
|
|
64
64
|
def name_already_exists?(form)
|
65
65
|
if form.new_record?
|
66
|
-
Motor::Form.exists?(['
|
66
|
+
Motor::Form.exists?(['name = ?', form.name])
|
67
67
|
else
|
68
|
-
Motor::Form.exists?(['
|
68
|
+
Motor::Form.exists?(['name = ? AND id != ?', form.name, form.id])
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|