motor-admin 0.1.52 → 0.1.53

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8798474d7c7dc20d6410dd00f13950997be5e3f5d67e1d2585a57af92cd8db10
4
- data.tar.gz: 90fcc0b1835fe56b78ecfcc28de03f9d4397b213f6e499afc626c3f4d13b1ef9
3
+ metadata.gz: 2484e6d98ef1891e59ab7bc0e50dc8337f0b99ae3fb35e2d5d72caf84020112c
4
+ data.tar.gz: 85a1e6334f83ccdd8e49b6f80ef52ff7ef8f169b586fc00b0745d281e1b75f9a
5
5
  SHA512:
6
- metadata.gz: c3a34e36e74e5004508e420ba4cdf95e2784d52647dfefccb64fc078b2785cbdd42a7aad84ca41f4c86e2c680b76516f219a41739b7d19601798dda4c9319e06
7
- data.tar.gz: 727c31fafba431b69e3206d0fb2cff568171760cd43b36b9a42e97a356d5e344c7cacb069c5e9e79899e0fa804f39fd122ae14e30aece4cb77ca64de31620c5f
6
+ metadata.gz: dabb17786ed10544c54246f0a460cb3507d9cca5cb8269aa4e0cf0962d69f55cb8f63870f0c6ecfe2810da7c174f2cce7f75702f3472be0221a02ad49babb159
7
+ data.tar.gz: 2a5c5b2c319248b692f6d662c510ca489066a192c613714c9e970352db3a06994d032d01052707799627bf81bca0b6422a399f8584925baa1658d44706043c67
@@ -9,22 +9,24 @@ module Motor
9
9
  before_action :build_query, only: :create
10
10
  authorize_resource :query, only: :create
11
11
 
12
- rescue_from 'ActiveRecord::StatementInvalid' do |e|
13
- render json: { errors: [{ detail: e.message }] }, status: :unprocessable_entity
14
- end
15
-
16
12
  def show
17
- render json: query_result_hash(query_result)
13
+ render_result
18
14
  end
19
15
 
20
16
  def create
21
- render json: query_result_hash(query_result)
17
+ render_result
22
18
  end
23
19
 
24
20
  private
25
21
 
26
- def query_result
27
- Queries::RunQuery.call(@query, variables_hash: params[:variables])
22
+ def render_result
23
+ query_result = Queries::RunQuery.call(@query, variables_hash: params[:variables])
24
+
25
+ if query_result.error
26
+ render json: { errors: [{ detail: query_result.error }] }, status: :unprocessable_entity
27
+ else
28
+ render json: query_result_hash(query_result)
29
+ end
28
30
  end
29
31
 
30
32
  def query_result_hash(query_result)
@@ -16,7 +16,7 @@ module Motor
16
16
  scope :active, -> { where(deleted_at: nil) }
17
17
 
18
18
  def result(variables_hash = {})
19
- result = Motor::Queries::RunQuery.call(self, variables_hash: variables_hash)
19
+ result = Motor::Queries::RunQuery.call!(self, variables_hash: variables_hash)
20
20
  column_names = result.columns.pluck(:name)
21
21
 
22
22
  result.data.map { |row| column_names.zip(row).to_h }
@@ -1,12 +1,12 @@
1
1
  class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
2
  def self.up
3
3
  create_table :motor_queries do |t|
4
- t.column :name, :text, null: false
4
+ t.column :name, :string, null: false
5
5
  t.column :description, :text
6
6
  t.column :sql_body, :text, null: false
7
7
  t.column :preferences, :text, null: false
8
8
  t.column :author_id, :bigint
9
- t.column :author_type, :text
9
+ t.column :author_type, :string
10
10
  t.column :deleted_at, :datetime
11
11
 
12
12
  t.timestamps
@@ -15,16 +15,15 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
15
15
  t.index 'name',
16
16
  name: 'motor_queries_name_unique_index',
17
17
  unique: true,
18
- where: 'deleted_at IS NULL',
19
- length: { name: 255 }
18
+ where: 'deleted_at IS NULL'
20
19
  end
21
20
 
22
21
  create_table :motor_dashboards do |t|
23
- t.column :title, :text, null: false
22
+ t.column :title, :string, null: false
24
23
  t.column :description, :text
25
24
  t.column :preferences, :text, null: false
26
25
  t.column :author_id, :bigint
27
- t.column :author_type, :text
26
+ t.column :author_type, :string
28
27
  t.column :deleted_at, :datetime
29
28
 
30
29
  t.timestamps
@@ -33,18 +32,17 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
33
32
  t.index 'title',
34
33
  name: 'motor_dashboards_title_unique_index',
35
34
  unique: true,
36
- where: 'deleted_at IS NULL',
37
- length: { title: 255 }
35
+ where: 'deleted_at IS NULL'
38
36
  end
39
37
 
40
38
  create_table :motor_forms do |t|
41
- t.column :name, :text, null: false
39
+ t.column :name, :string, null: false
42
40
  t.column :description, :text
43
41
  t.column :api_path, :text, null: false
44
- t.column :http_method, :text, null: false
42
+ t.column :http_method, :string, null: false
45
43
  t.column :preferences, :text, null: false
46
44
  t.column :author_id, :bigint
47
- t.column :author_type, :text
45
+ t.column :author_type, :string
48
46
  t.column :deleted_at, :datetime
49
47
 
50
48
  t.timestamps
@@ -53,12 +51,11 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
53
51
  t.index 'name',
54
52
  name: 'motor_forms_name_unique_index',
55
53
  unique: true,
56
- where: 'deleted_at IS NULL',
57
- length: { name: 255 }
54
+ where: 'deleted_at IS NULL'
58
55
  end
59
56
 
60
57
  create_table :motor_resources do |t|
61
- t.column :name, :text, null: false, index: { unique: true, length: 255 }
58
+ t.column :name, :string, null: false, index: { unique: true }
62
59
  t.column :preferences, :text, null: false
63
60
 
64
61
  t.timestamps
@@ -67,7 +64,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
67
64
  end
68
65
 
69
66
  create_table :motor_configs do |t|
70
- t.column :key, :text, null: false, index: { unique: true, length: 255 }
67
+ t.column :key, :string, null: false, index: { unique: true }
71
68
  t.column :value, :text, null: false
72
69
 
73
70
  t.timestamps
@@ -77,13 +74,13 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
77
74
 
78
75
  create_table :motor_alerts do |t|
79
76
  t.references :query, null: false, foreign_key: { to_table: :motor_queries }, index: true
80
- t.column :name, :text, null: false
77
+ t.column :name, :string, null: false
81
78
  t.column :description, :text
82
79
  t.column :to_emails, :text, null: false
83
80
  t.column :is_enabled, :boolean, null: false, default: true
84
81
  t.column :preferences, :text, null: false
85
82
  t.column :author_id, :bigint
86
- t.column :author_type, :text
83
+ t.column :author_type, :string
87
84
  t.column :deleted_at, :datetime
88
85
 
89
86
  t.timestamps
@@ -92,65 +89,59 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
92
89
  t.index 'name',
93
90
  name: 'motor_alerts_name_unique_index',
94
91
  unique: true,
95
- where: 'deleted_at IS NULL',
96
- length: { name: 255 }
92
+ where: 'deleted_at IS NULL'
97
93
  end
98
94
 
99
95
  create_table :motor_alert_locks do |t|
100
96
  t.references :alert, null: false, foreign_key: { to_table: :motor_alerts }
101
- t.column :lock_timestamp, :text, null: false
97
+ t.column :lock_timestamp, :string, null: false
102
98
 
103
99
  t.timestamps
104
100
 
105
- t.index %i[alert_id lock_timestamp], unique: true, length: { lock_timestamp: 255 }
101
+ t.index %i[alert_id lock_timestamp], unique: true
106
102
  end
107
103
 
108
104
  create_table :motor_tags do |t|
109
- t.column :name, :text, null: false
105
+ t.column :name, :string, null: false
110
106
 
111
107
  t.timestamps
112
108
 
113
109
  t.index 'name',
114
110
  name: 'motor_tags_name_unique_index',
115
- unique: true,
116
- length: { name: 255 }
111
+ unique: true
117
112
  end
118
113
 
119
114
  create_table :motor_taggable_tags do |t|
120
115
  t.references :tag, null: false, foreign_key: { to_table: :motor_tags }, index: true
121
116
  t.column :taggable_id, :bigint, null: false
122
- t.column :taggable_type, :text, null: false
117
+ t.column :taggable_type, :string, null: false
123
118
 
124
119
  t.index %i[taggable_id taggable_type tag_id],
125
120
  name: 'motor_polymorphic_association_tag_index',
126
- unique: true,
127
- length: { taggable_type: 255 }
121
+ unique: true
128
122
  end
129
123
 
130
124
  create_table :motor_audits do |t|
131
125
  t.column :auditable_id, :bigint
132
- t.column :auditable_type, :text
126
+ t.column :auditable_type, :string
133
127
  t.column :associated_id, :bigint
134
- t.column :associated_type, :text
128
+ t.column :associated_type, :string
135
129
  t.column :user_id, :bigint
136
- t.column :user_type, :text
137
- t.column :username, :text
138
- t.column :action, :text
130
+ t.column :user_type, :string
131
+ t.column :username, :string
132
+ t.column :action, :string
139
133
  t.column :audited_changes, :text
140
134
  t.column :version, :bigint, default: 0
141
135
  t.column :comment, :text
142
- t.column :remote_address, :text
143
- t.column :request_uuid, :text
136
+ t.column :remote_address, :string
137
+ t.column :request_uuid, :string
144
138
  t.column :created_at, :datetime
145
139
  end
146
140
 
147
- add_index :motor_audits, %i[auditable_type auditable_id version], name: 'motor_auditable_index',
148
- length: { auditable_type: 255 }
149
- add_index :motor_audits, %i[associated_type associated_id], name: 'motor_auditable_associated_index',
150
- length: { associated_type: 255 }
151
- add_index :motor_audits, %i[user_id user_type], name: 'motor_auditable_user_index',
152
- length: { user_type: 255 }
153
- add_index :motor_audits, :request_uuid, length: { request_uuid: 255 }
141
+ add_index :motor_audits, %i[auditable_type auditable_id version], name: 'motor_auditable_index'
142
+ add_index :motor_audits, %i[associated_type associated_id], name: 'motor_auditable_associated_index'
143
+ add_index :motor_audits, %i[user_id user_type], name: 'motor_auditable_user_index'
144
+ add_index :motor_audits, :request_uuid
154
145
  add_index :motor_audits, :created_at
155
146
  end
156
147
 
data/lib/motor/admin.rb CHANGED
@@ -66,12 +66,12 @@ module Motor
66
66
  end
67
67
 
68
68
  initializer 'motor.active_storage.extensions' do
69
- next unless defined?(ActiveStorage::Engine)
70
-
71
- ActiveStorage::Engine.eager_load!
69
+ config.after_initialize do
70
+ next unless defined?(ActiveStorage::Engine)
72
71
 
73
- ActiveStorage::Attachment.include(Motor::ActiveRecordUtils::ActiveStorageLinksExtension)
74
- ActiveStorage::Blob.singleton_class.prepend(Motor::ActiveRecordUtils::ActiveStorageBlobPatch)
72
+ ActiveStorage::Attachment.include(Motor::ActiveRecordUtils::ActiveStorageLinksExtension)
73
+ ActiveStorage::Blob.singleton_class.prepend(Motor::ActiveRecordUtils::ActiveStorageBlobPatch)
74
+ end
75
75
  end
76
76
  end
77
77
  end
data/lib/motor/assets.rb CHANGED
@@ -35,6 +35,8 @@ module Motor
35
35
  def load_from_disk(filename, gzip:)
36
36
  filename += '.gz' if gzip
37
37
 
38
+ raise InvalidPathError if filename.include?('..')
39
+
38
40
  path = ASSETS_PATH.join(filename)
39
41
 
40
42
  raise InvalidPathError unless path.to_s.starts_with?(ASSETS_PATH.to_s)
@@ -5,19 +5,24 @@ module Motor
5
5
  module RunQuery
6
6
  DEFAULT_LIMIT = 100_000
7
7
 
8
- QueryResult = Struct.new(:data, :columns, keyword_init: true)
8
+ QueryResult = Struct.new(:data, :columns, :error, keyword_init: true)
9
+
10
+ WITH_STATEMENT_START = 'WITH __query__ AS ('
9
11
 
10
12
  WITH_STATEMENT_TEMPLATE = <<~SQL
11
- WITH __query__ AS (%<sql_body>s) SELECT * FROM __query__ LIMIT %<limit>s;
13
+ #{WITH_STATEMENT_START}%<sql_body>s
14
+ ) SELECT * FROM __query__ LIMIT %<limit>s;
12
15
  SQL
13
16
 
17
+ PG_ERROR_REGEXP = /\APG.+ERROR:/.freeze
18
+
14
19
  module_function
15
20
 
16
21
  # @param query [Motor::Query]
17
22
  # @param variables_hash [Hash]
18
23
  # @param limit [Integer]
19
24
  # @return [Motor::Queries::RunQuery::QueryResult]
20
- def call(query, variables_hash: nil, limit: DEFAULT_LIMIT)
25
+ def call!(query, variables_hash: nil, limit: DEFAULT_LIMIT)
21
26
  variables_hash ||= {}
22
27
 
23
28
  result = execute_query(query, limit, variables_hash)
@@ -25,6 +30,22 @@ module Motor
25
30
  QueryResult.new(data: result.rows, columns: build_columns_hash(result))
26
31
  end
27
32
 
33
+ # @param query [Motor::Query]
34
+ # @param variables_hash [Hash]
35
+ # @param limit [Integer]
36
+ # @return [Motor::Queries::RunQuery::QueryResult]
37
+ def call(query, variables_hash: nil, limit: DEFAULT_LIMIT)
38
+ call!(query, variables_hash: variables_hash, limit: limit)
39
+ rescue ActiveRecord::StatementInvalid => e
40
+ QueryResult.new(error: build_error_message(e))
41
+ end
42
+
43
+ # @param exception [ActiveRecord::StatementInvalid]
44
+ # @return [String]
45
+ def build_error_message(exception)
46
+ exception.message.sub(WITH_STATEMENT_START, '').sub(PG_ERROR_REGEXP, '').strip.upcase_first
47
+ end
48
+
28
49
  # @param query [Motor::Query]
29
50
  # @param limit [Integer]
30
51
  # @param variables_hash [Hash]
data/lib/motor/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Motor
4
- VERSION = '0.1.52'
4
+ VERSION = '0.1.53'
5
5
  end
@@ -2068,11 +2068,11 @@
2068
2068
  "mail-opened.svg": "icons/mail-opened.svg",
2069
2069
  "mail.svg": "icons/mail.svg",
2070
2070
  "mailbox.svg": "icons/mailbox.svg",
2071
- "main-36a9ee6a9b0427a77d87.css.gz": "main-36a9ee6a9b0427a77d87.css.gz",
2072
- "main-36a9ee6a9b0427a77d87.js.LICENSE.txt": "main-36a9ee6a9b0427a77d87.js.LICENSE.txt",
2073
- "main-36a9ee6a9b0427a77d87.js.gz": "main-36a9ee6a9b0427a77d87.js.gz",
2074
- "main.css": "main-36a9ee6a9b0427a77d87.css",
2075
- "main.js": "main-36a9ee6a9b0427a77d87.js",
2071
+ "main-67fbb3a8f6a6388434c8.css.gz": "main-67fbb3a8f6a6388434c8.css.gz",
2072
+ "main-67fbb3a8f6a6388434c8.js.LICENSE.txt": "main-67fbb3a8f6a6388434c8.js.LICENSE.txt",
2073
+ "main-67fbb3a8f6a6388434c8.js.gz": "main-67fbb3a8f6a6388434c8.js.gz",
2074
+ "main.css": "main-67fbb3a8f6a6388434c8.css",
2075
+ "main.js": "main-67fbb3a8f6a6388434c8.js",
2076
2076
  "man.svg": "icons/man.svg",
2077
2077
  "manual-gearbox.svg": "icons/manual-gearbox.svg",
2078
2078
  "map-2.svg": "icons/map-2.svg",
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.1.52
4
+ version: 0.1.53
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-05-29 00:00:00.000000000 Z
11
+ date: 2021-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord-filter
@@ -108,7 +108,10 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '5.2'
111
- description: Admin UI and Business Analytics.
111
+ description: |
112
+ Motor Admin allows to create a flexible admin panel with writing less code.
113
+ All customizations to the admin panel can be made directly in the UI without
114
+ the need of writing any configurations code.
112
115
  email:
113
116
  - pete.matsy@gmail.com
114
117
  executables: []
@@ -1481,8 +1484,8 @@ files:
1481
1484
  - ui/dist/icons/zoom-money.svg.gz
1482
1485
  - ui/dist/icons/zoom-out.svg.gz
1483
1486
  - ui/dist/icons/zoom-question.svg.gz
1484
- - ui/dist/main-36a9ee6a9b0427a77d87.css.gz
1485
- - ui/dist/main-36a9ee6a9b0427a77d87.js.gz
1487
+ - ui/dist/main-67fbb3a8f6a6388434c8.css.gz
1488
+ - ui/dist/main-67fbb3a8f6a6388434c8.js.gz
1486
1489
  - ui/dist/manifest.json
1487
1490
  homepage:
1488
1491
  licenses:
@@ -1506,5 +1509,5 @@ requirements: []
1506
1509
  rubygems_version: 3.2.3
1507
1510
  signing_key:
1508
1511
  specification_version: 4
1509
- summary: Admin UI and Business Analytics
1512
+ summary: Low-code Admin panel and Business intelligence
1510
1513
  test_files: []