motor-admin 0.1.54 → 0.1.60
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/README.md +6 -4
- data/app/controllers/concerns/motor/current_ability.rb +21 -0
- data/app/controllers/concerns/motor/current_user_method.rb +8 -7
- data/app/controllers/motor/alerts_controller.rb +4 -4
- data/app/controllers/motor/api_base_controller.rb +1 -12
- data/app/controllers/motor/application_controller.rb +1 -0
- data/app/controllers/motor/audits_controller.rb +1 -1
- data/app/controllers/motor/auth_tokens_controller.rb +36 -0
- data/app/controllers/motor/configs_controller.rb +2 -2
- data/app/controllers/motor/dashboards_controller.rb +8 -4
- data/app/controllers/motor/data_controller.rb +9 -4
- data/app/controllers/motor/forms_controller.rb +4 -4
- data/app/controllers/motor/icons_controller.rb +2 -0
- data/app/controllers/motor/queries_controller.rb +4 -4
- data/app/controllers/motor/resource_methods_controller.rb +2 -0
- data/app/controllers/motor/resources_controller.rb +2 -2
- data/app/controllers/motor/run_queries_controller.rb +12 -1
- data/app/controllers/motor/ui_controller.rb +1 -1
- data/app/views/motor/ui/show.html.erb +1 -1
- data/config/routes.rb +1 -0
- data/lib/motor.rb +1 -0
- data/lib/motor/admin.rb +20 -0
- data/lib/motor/api_query/build_json.rb +101 -47
- data/lib/motor/api_query/filter.rb +2 -0
- data/lib/motor/api_query/search.rb +1 -0
- data/lib/motor/assets.rb +10 -1
- data/lib/motor/build_schema.rb +3 -1
- data/lib/motor/build_schema/active_storage_attachment_schema.rb +1 -0
- data/lib/motor/build_schema/apply_permissions.rb +50 -0
- data/lib/motor/build_schema/find_display_column.rb +1 -0
- data/lib/motor/build_schema/find_icon.rb +5 -1
- data/lib/motor/cancan_utils.rb +7 -0
- data/lib/motor/cancan_utils/ability_patch.rb +29 -0
- data/lib/motor/cancan_utils/can_manage_all.rb +14 -0
- data/lib/motor/configs/build_ui_app_tag.rb +26 -16
- data/lib/motor/configs/load_from_cache.rb +20 -8
- data/lib/motor/queries/run_query.rb +7 -3
- data/lib/motor/version.rb +1 -1
- data/ui/dist/{main-67fbb3a8f6a6388434c8.css.gz → main-96c4a62d2fb789ab1080.css.gz} +0 -0
- data/ui/dist/main-96c4a62d2fb789ab1080.js.gz +0 -0
- data/ui/dist/manifest.json +5 -5
- metadata +12 -7
- data/app/controllers/motor/schemas_controller.rb +0 -11
- data/ui/dist/main-67fbb3a8f6a6388434c8.js.gz +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d709fb5b88f56a20cb9c2f906f3540b53278e04becc96598556dba70a0dcb4f
|
4
|
+
data.tar.gz: 5ffca9ae9451e2aa373957116c1b9b6607f5aba3bc1fa1cee555682c1a2987be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 944babec34990e1889a52e76f652ca725dda31f4bcbb75aefc47cb715beca9a1a6127d6c5aa1e70437beafdf6a0c9cfaaaf3cf29a901524980812e23134cefaa
|
7
|
+
data.tar.gz: c79c99d0491e3c02c05296f0ace0ace54bbeeef1cd11f927b49f5edd814503f3e5f0f5a017c184e97bbce9a4b02b7279db36333a8b3fb796fb6125f283e8604a
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
# ⚡ Motor Admin
|
1
|
+
# ⚡ Motor Admin ⚡
|
2
2
|
|
3
3
|
Low-code Admin panel and Business intelligence Rails engine **(no DSL - configurable from the UI)**.
|
4
4
|
|
5
|
-
🤓 [Demo App](https://motor-admin.herokuapp.com/demo) | [Features overview](https://www.youtube.com/watch?v=ngVoci8Hll4&list=PLu7llEMh0KcOkR3Uy_RJT0cXPZQKAYVsq&index=1)
|
5
|
+
🤓 [Demo App](https://motor-admin.herokuapp.com/demo) | 👀 [Features overview](https://www.youtube.com/watch?v=ngVoci8Hll4&list=PLu7llEMh0KcOkR3Uy_RJT0cXPZQKAYVsq&index=1) | ⭐ [Stargathers](https://github.com/omohokcoj/motor-admin/stargazers)
|
6
6
|
|
7
7
|
[](https://motor-admin.herokuapp.com/demo)
|
8
8
|
|
@@ -32,6 +32,7 @@ $ rails motor:install && rake db:migrate
|
|
32
32
|
* [Data visualization](#data-visualization)
|
33
33
|
* [Dashboards](#dashboards)
|
34
34
|
* [Email alerts](#email-alerts)
|
35
|
+
* [Authorization](#authorization)
|
35
36
|
* [Intelligence search](#intelligence-search)
|
36
37
|
* [Optimized for mobile](#optimized-for-mobile)
|
37
38
|
* [Configurations sync between environments](#configurations-sync)
|
@@ -90,6 +91,9 @@ Sender address can be specified using `MOTOR_ALERTS_FROM_ADDRESS` environment va
|
|
90
91
|
|
91
92
|
Intelligence search can be opened via the top right corner button or using <kbd>Cmd</kbd> + <kbd>P</kbd> shortcut.
|
92
93
|
|
94
|
+
### Authorization
|
95
|
+
|
96
|
+
Motor Admin allows to set row-level and column-level permissions via [cancan](https://github.com/CanCanCommunity/cancancan) gem. Admin UI permissions should be defined in `app/models/motor/ability.rb` file in `Motor::Ability` class. See [Motor Admin guide](https://github.com/omohokcoj/motor-admin/blob/master/guides/defining_permissions.md) and [CanCan documentation](https://github.com/CanCanCommunity/cancancan/blob/develop/docs/Defining-Abilities.md) to learn how to define user permissions.
|
93
97
|
|
94
98
|
### Optimized for Mobile
|
95
99
|
|
@@ -141,8 +145,6 @@ MOTOR_DEVELOPMENT=true rails s
|
|
141
145
|
|
142
146
|
## Comming Soon
|
143
147
|
|
144
|
-
* User groups
|
145
|
-
* Row-level permissions
|
146
148
|
* Multiple databases
|
147
149
|
* NoSQL data sources
|
148
150
|
* Pro Bussines intelligence features
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Motor
|
4
|
+
module CurrentAbility
|
5
|
+
def current_ability
|
6
|
+
@current_ability ||=
|
7
|
+
if defined?(Motor::Ability) && current_user
|
8
|
+
klass = Motor::Ability.dup.tap do |k|
|
9
|
+
k.prepend(Motor::CancanUtils::AbilityPatch)
|
10
|
+
end
|
11
|
+
|
12
|
+
params = [current_user]
|
13
|
+
params << request if Motor::Ability.instance_method(:initialize).arity == 2
|
14
|
+
|
15
|
+
klass.new(*params)
|
16
|
+
else
|
17
|
+
Motor::CancanUtils::CanManageAll.new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -3,13 +3,14 @@
|
|
3
3
|
module Motor
|
4
4
|
module CurrentUserMethod
|
5
5
|
def current_user
|
6
|
-
|
7
|
-
current_admin
|
8
|
-
|
9
|
-
current_admin_user
|
10
|
-
|
11
|
-
super
|
12
|
-
|
6
|
+
@current_user ||=
|
7
|
+
if defined?(current_admin)
|
8
|
+
current_admin
|
9
|
+
elsif defined?(current_admin_user)
|
10
|
+
current_admin_user
|
11
|
+
elsif defined?(super)
|
12
|
+
super
|
13
|
+
end
|
13
14
|
end
|
14
15
|
end
|
15
16
|
end
|
@@ -10,11 +10,11 @@ module Motor
|
|
10
10
|
authorize_resource :alert, only: :create
|
11
11
|
|
12
12
|
def index
|
13
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@alerts.active, params) }
|
13
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@alerts.active, params, current_ability) }
|
14
14
|
end
|
15
15
|
|
16
16
|
def show
|
17
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@alert, params) }
|
17
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@alert, params, current_ability) }
|
18
18
|
end
|
19
19
|
|
20
20
|
def create
|
@@ -25,7 +25,7 @@ module Motor
|
|
25
25
|
Motor::Alerts::ScheduledAlertsCache.clear
|
26
26
|
Motor::Configs::WriteToFile.call
|
27
27
|
|
28
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@alert, params) }
|
28
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@alert, params, current_ability) }
|
29
29
|
end
|
30
30
|
rescue Motor::Alerts::Persistance::InvalidInterval
|
31
31
|
invalid_interval_response
|
@@ -36,7 +36,7 @@ module Motor
|
|
36
36
|
Motor::Alerts::ScheduledAlertsCache.clear
|
37
37
|
Motor::Configs::WriteToFile.call
|
38
38
|
|
39
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@alert, params) }
|
39
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@alert, params, current_ability) }
|
40
40
|
rescue Motor::Alerts::Persistance::NameAlreadyExists
|
41
41
|
name_already_exists_response
|
42
42
|
rescue Motor::Alerts::Persistance::InvalidInterval
|
@@ -3,14 +3,7 @@
|
|
3
3
|
module Motor
|
4
4
|
class ApiBaseController < ActionController::API
|
5
5
|
include Motor::CurrentUserMethod
|
6
|
-
|
7
|
-
class CanCanAbilityManageAll
|
8
|
-
include CanCan::Ability
|
9
|
-
|
10
|
-
def initialize(_)
|
11
|
-
can :manage, :all
|
12
|
-
end
|
13
|
-
end
|
6
|
+
include Motor::CurrentAbility
|
14
7
|
|
15
8
|
unless Rails.env.test?
|
16
9
|
rescue_from StandardError do |e|
|
@@ -19,9 +12,5 @@ module Motor
|
|
19
12
|
render json: { errors: [e.message] }, status: :internal_server_error
|
20
13
|
end
|
21
14
|
end
|
22
|
-
|
23
|
-
def current_ability
|
24
|
-
CanCanAbilityManageAll.new(current_user)
|
25
|
-
end
|
26
15
|
end
|
27
16
|
end
|
@@ -8,7 +8,7 @@ module Motor
|
|
8
8
|
audits = Motor::ApiQuery.call(@audits, params)
|
9
9
|
|
10
10
|
render json: {
|
11
|
-
data: Motor::ApiQuery::BuildJson.call(audits, params),
|
11
|
+
data: Motor::ApiQuery::BuildJson.call(audits, params, current_ability),
|
12
12
|
meta: Motor::ApiQuery::BuildMeta.call(audits, params)
|
13
13
|
}
|
14
14
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Motor
|
4
|
+
class AuthTokensController < ApiBaseController
|
5
|
+
GENERIC_TOKEN_TTL = 2.hours
|
6
|
+
|
7
|
+
skip_authorization_check
|
8
|
+
|
9
|
+
def create
|
10
|
+
return render json: {} unless current_user
|
11
|
+
|
12
|
+
if defined?(Devise::JWT)
|
13
|
+
respond_with_devise_jwt
|
14
|
+
elsif defined?(JWT)
|
15
|
+
respond_with_generic_jwt
|
16
|
+
else
|
17
|
+
render json: {}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def respond_with_devise_jwt
|
24
|
+
warden.set_user(current_user)
|
25
|
+
|
26
|
+
render json: { token: request.env['warden-jwt_auth.token'] }
|
27
|
+
end
|
28
|
+
|
29
|
+
def respond_with_generic_jwt
|
30
|
+
payload = { uid: current_user.id, exp: GENERIC_TOKEN_TTL.from_now.to_i }
|
31
|
+
token = JWT.encode(payload, Rails.application.secrets.secret_key_base)
|
32
|
+
|
33
|
+
render json: { token: token }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -7,7 +7,7 @@ module Motor
|
|
7
7
|
load_and_authorize_resource
|
8
8
|
|
9
9
|
def index
|
10
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@configs, params) }
|
10
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@configs, params, current_ability) }
|
11
11
|
end
|
12
12
|
|
13
13
|
def create
|
@@ -19,7 +19,7 @@ module Motor
|
|
19
19
|
@config.save!
|
20
20
|
Motor::Configs::WriteToFile.call
|
21
21
|
|
22
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@config, params) }
|
22
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@config, params, current_ability) }
|
23
23
|
rescue ActiveRecord::RecordNotUnique
|
24
24
|
retry
|
25
25
|
end
|
@@ -10,11 +10,11 @@ module Motor
|
|
10
10
|
authorize_resource :dashboard, only: :create
|
11
11
|
|
12
12
|
def index
|
13
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@dashboards.active, params) }
|
13
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@dashboards.active, params, current_ability) }
|
14
14
|
end
|
15
15
|
|
16
16
|
def show
|
17
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@dashboard, params) }
|
17
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@dashboard, params, current_ability) }
|
18
18
|
end
|
19
19
|
|
20
20
|
def create
|
@@ -24,7 +24,7 @@ module Motor
|
|
24
24
|
ApplicationRecord.transaction { @dashboard.save! }
|
25
25
|
Motor::Configs::WriteToFile.call
|
26
26
|
|
27
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@dashboard, params) }
|
27
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@dashboard, params, current_ability) }
|
28
28
|
end
|
29
29
|
rescue ActiveRecord::RecordNotUnique
|
30
30
|
retry
|
@@ -34,7 +34,7 @@ module Motor
|
|
34
34
|
Motor::Dashboards::Persistance.update_from_params!(@dashboard, dashboard_params)
|
35
35
|
Motor::Configs::WriteToFile.call
|
36
36
|
|
37
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@dashboard, params) }
|
37
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@dashboard, params, current_ability) }
|
38
38
|
rescue Motor::Dashboards::Persistance::TitleAlreadyExists
|
39
39
|
render json: { errors: [{ source: 'title', detail: 'Title already exists' }] }, status: :unprocessable_entity
|
40
40
|
end
|
@@ -51,6 +51,10 @@ module Motor
|
|
51
51
|
|
52
52
|
def build_dashboard
|
53
53
|
@dashboard = Motor::Dashboards::Persistance.build_from_params(dashboard_params)
|
54
|
+
|
55
|
+
@dashboard.define_singleton_method(:tags) do
|
56
|
+
taggable_tags.map(&:tag)
|
57
|
+
end
|
54
58
|
end
|
55
59
|
|
56
60
|
def dashboard_params
|
@@ -11,19 +11,19 @@ module Motor
|
|
11
11
|
@resources = Motor::ApiQuery.call(@resources, params)
|
12
12
|
|
13
13
|
render json: {
|
14
|
-
data: Motor::ApiQuery::BuildJson.call(@resources, params),
|
14
|
+
data: Motor::ApiQuery::BuildJson.call(@resources, params, current_ability),
|
15
15
|
meta: Motor::ApiQuery::BuildMeta.call(@resources, params)
|
16
16
|
}
|
17
17
|
end
|
18
18
|
|
19
19
|
def show
|
20
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@resource, params) }
|
20
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@resource, params, current_ability) }
|
21
21
|
end
|
22
22
|
|
23
23
|
def create
|
24
24
|
@resource.save!
|
25
25
|
|
26
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@resource, params) }
|
26
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@resource, params, current_ability) }
|
27
27
|
rescue ActiveRecord::RecordInvalid
|
28
28
|
render json: { errors: @resource.errors }, status: :unprocessable_entity
|
29
29
|
end
|
@@ -31,7 +31,7 @@ module Motor
|
|
31
31
|
def update
|
32
32
|
@resource.update!(resource_params)
|
33
33
|
|
34
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@resource, params) }
|
34
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@resource, params, current_ability) }
|
35
35
|
rescue ActiveRecord::RecordInvalid
|
36
36
|
render json: { errors: @resource.errors }, status: :unprocessable_entity
|
37
37
|
end
|
@@ -47,6 +47,11 @@ module Motor
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def execute
|
50
|
+
resource_preferences = Motor::Resource.find_by(name: @resource.class.name.underscore).preferences
|
51
|
+
resource_action = resource_preferences[:actions].find { |a| a[:preferences][:method_name] == params[:method] }
|
52
|
+
|
53
|
+
authorize!(resource_action[:name].to_sym, @resource)
|
54
|
+
|
50
55
|
@resource.public_send(params[:method].to_sym)
|
51
56
|
|
52
57
|
head :ok
|
@@ -10,11 +10,11 @@ module Motor
|
|
10
10
|
authorize_resource :form, only: :create
|
11
11
|
|
12
12
|
def index
|
13
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@forms.active, params) }
|
13
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@forms.active, params, current_ability) }
|
14
14
|
end
|
15
15
|
|
16
16
|
def show
|
17
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@form, params) }
|
17
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@form, params, current_ability) }
|
18
18
|
end
|
19
19
|
|
20
20
|
def create
|
@@ -24,7 +24,7 @@ module Motor
|
|
24
24
|
ApplicationRecord.transaction { @form.save! }
|
25
25
|
Motor::Configs::WriteToFile.call
|
26
26
|
|
27
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@form, params) }
|
27
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@form, params, current_ability) }
|
28
28
|
end
|
29
29
|
rescue ActiveRecord::RecordNotUnique
|
30
30
|
retry
|
@@ -34,7 +34,7 @@ module Motor
|
|
34
34
|
Motor::Forms::Persistance.update_from_params!(@form, form_params)
|
35
35
|
Motor::Configs::WriteToFile.call
|
36
36
|
|
37
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@form, params) }
|
37
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@form, params, current_ability) }
|
38
38
|
rescue Motor::Forms::Persistance::NameAlreadyExists
|
39
39
|
render json: { errors: [{ source: 'name', detail: 'Name already exists' }] }, status: :unprocessable_entity
|
40
40
|
end
|
@@ -10,11 +10,11 @@ module Motor
|
|
10
10
|
authorize_resource :query, only: :create
|
11
11
|
|
12
12
|
def index
|
13
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@queries.active, params) }
|
13
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@queries.active, params, current_ability) }
|
14
14
|
end
|
15
15
|
|
16
16
|
def show
|
17
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@query, params) }
|
17
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@query, params, current_ability) }
|
18
18
|
end
|
19
19
|
|
20
20
|
def create
|
@@ -24,7 +24,7 @@ module Motor
|
|
24
24
|
ApplicationRecord.transaction { @query.save! }
|
25
25
|
Motor::Configs::WriteToFile.call
|
26
26
|
|
27
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@query, params) }
|
27
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@query, params, current_ability) }
|
28
28
|
end
|
29
29
|
rescue ActiveRecord::RecordNotUnique
|
30
30
|
retry
|
@@ -34,7 +34,7 @@ module Motor
|
|
34
34
|
Motor::Queries::Persistance.update_from_params!(@query, query_params)
|
35
35
|
Motor::Configs::WriteToFile.call
|
36
36
|
|
37
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@query, params) }
|
37
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@query, params, current_ability) }
|
38
38
|
rescue Motor::Queries::Persistance::NameAlreadyExists
|
39
39
|
render json: { errors: [{ source: 'name', detail: 'Name already exists' }] }, status: :unprocessable_entity
|
40
40
|
end
|
@@ -7,14 +7,14 @@ module Motor
|
|
7
7
|
load_and_authorize_resource
|
8
8
|
|
9
9
|
def index
|
10
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@resources, params) }
|
10
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@resources, params, current_ability) }
|
11
11
|
end
|
12
12
|
|
13
13
|
def create
|
14
14
|
Motor::BuildSchema::PersistResourceConfigs.call(@resource)
|
15
15
|
Motor::Configs::WriteToFile.call
|
16
16
|
|
17
|
-
render json: { data: Motor::ApiQuery::BuildJson.call(@resource, params) }
|
17
|
+
render json: { data: Motor::ApiQuery::BuildJson.call(@resource, params, current_ability) }
|
18
18
|
end
|
19
19
|
|
20
20
|
private
|
@@ -20,7 +20,8 @@ module Motor
|
|
20
20
|
private
|
21
21
|
|
22
22
|
def render_result
|
23
|
-
|
23
|
+
variables = params.fetch(:variables, {}).merge(current_user_variables)
|
24
|
+
query_result = Queries::RunQuery.call(@query, variables_hash: variables)
|
24
25
|
|
25
26
|
if query_result.error
|
26
27
|
render json: { errors: [{ detail: query_result.error }] }, status: :unprocessable_entity
|
@@ -29,6 +30,16 @@ module Motor
|
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
33
|
+
def current_user_variables
|
34
|
+
return {} unless current_user
|
35
|
+
|
36
|
+
current_user
|
37
|
+
.attributes
|
38
|
+
.slice('id', 'email')
|
39
|
+
.transform_keys { |key| "current_user_#{key}" }
|
40
|
+
.compact
|
41
|
+
end
|
42
|
+
|
32
43
|
def query_result_hash(query_result)
|
33
44
|
{
|
34
45
|
data: query_result.data,
|
@@ -1 +1 @@
|
|
1
|
-
<%= raw(Motor::Configs::BuildUiAppTag.call(current_user)) %>
|
1
|
+
<%= raw(Motor::Configs::BuildUiAppTag.call(current_user, current_ability)) %>
|
data/config/routes.rb
CHANGED
@@ -5,6 +5,7 @@ Motor::Admin.routes.draw do
|
|
5
5
|
scope 'api', as: :api do
|
6
6
|
resources :run_queries, only: %i[show create]
|
7
7
|
resources :send_alerts, only: %i[create]
|
8
|
+
resources :auth_tokens, only: %i[create]
|
8
9
|
resources :queries, only: %i[index show create update destroy]
|
9
10
|
resources :tags, only: %i[index]
|
10
11
|
resources :configs, only: %i[index create]
|
data/lib/motor.rb
CHANGED
data/lib/motor/admin.rb
CHANGED
@@ -65,10 +65,30 @@ module Motor
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
+
initializer 'warden.configure.dispatch_requests' do
|
69
|
+
next unless defined?(Warden::JWTAuth)
|
70
|
+
|
71
|
+
config.after_initialize do
|
72
|
+
Warden::JWTAuth.configure do |config|
|
73
|
+
config.dispatch_requests += [
|
74
|
+
['POST', /\A#{Regexp.escape(Motor::Admin.routes.url_helpers.motor_api_auth_tokens_path)}\z/]
|
75
|
+
]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
68
80
|
initializer 'motor.active_storage.extensions' do
|
69
81
|
config.after_initialize do
|
70
82
|
next unless defined?(ActiveStorage::Engine)
|
71
83
|
|
84
|
+
ActiveSupport.on_load(:active_storage_attachment) do
|
85
|
+
ActiveStorage::Attachment.include(Motor::ActiveRecordUtils::ActiveStorageLinksExtension)
|
86
|
+
end
|
87
|
+
|
88
|
+
ActiveSupport.on_load(:active_storage_blob) do
|
89
|
+
ActiveStorage::Blob.singleton_class.prepend(Motor::ActiveRecordUtils::ActiveStorageBlobPatch)
|
90
|
+
end
|
91
|
+
|
72
92
|
ActiveStorage::Attachment.include(Motor::ActiveRecordUtils::ActiveStorageLinksExtension)
|
73
93
|
ActiveStorage::Blob.singleton_class.prepend(Motor::ActiveRecordUtils::ActiveStorageBlobPatch)
|
74
94
|
end
|
@@ -5,83 +5,90 @@ module Motor
|
|
5
5
|
module BuildJson
|
6
6
|
module_function
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
# @param rel [ActiveRecord::Base, ActiveRecord::Relation]
|
9
|
+
# @param params [Hash]
|
10
|
+
# @param current_ability [CanCan::Ability]
|
11
|
+
# @return [Hash]
|
12
|
+
def call(rel, params, current_ability = Motor::CancanUtils::CanManageAll.new)
|
13
|
+
rel = rel.none if limit_zero_params?(params)
|
11
14
|
rel = rel.preload_associations_lazily if rel.is_a?(ActiveRecord::Relation)
|
12
15
|
|
13
|
-
|
14
|
-
|
15
|
-
assign_include_params(json_params, rel, params)
|
16
|
-
assign_fields_params(json_params, rel, params)
|
17
|
-
|
18
|
-
rel.as_json(json_params)
|
19
|
-
end
|
16
|
+
model = rel.is_a?(ActiveRecord::Relation) ? rel.klass : rel.class
|
20
17
|
|
21
|
-
|
22
|
-
|
18
|
+
include_hash = build_include_hash(params['include'])
|
19
|
+
models_index = build_models_index(model, include_hash)
|
23
20
|
|
24
|
-
|
21
|
+
json_params = normalize_include_params(include_hash)
|
25
22
|
|
26
|
-
|
27
|
-
include_params =
|
28
|
-
include_params.split(',').reduce({}) do |accumulator, path|
|
29
|
-
hash = {}
|
23
|
+
assign_fields_params!(json_params, model, params, current_ability, models_index)
|
30
24
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
acc[part] = acc_hash
|
25
|
+
rel.as_json(json_params.with_indifferent_access)
|
26
|
+
end
|
35
27
|
|
36
|
-
|
37
|
-
|
28
|
+
# @param include_params [Hash]
|
29
|
+
# @return [Hash]
|
30
|
+
def build_include_hash(include_params)
|
31
|
+
return {} if include_params.blank?
|
38
32
|
|
39
|
-
|
40
|
-
|
33
|
+
if include_params.is_a?(String)
|
34
|
+
build_hash_from_string_path(include_params)
|
35
|
+
else
|
36
|
+
include_params
|
41
37
|
end
|
42
|
-
|
43
|
-
json_params.deep_merge!(normalize_include_params(include_params))
|
44
38
|
end
|
45
39
|
|
46
|
-
|
40
|
+
# @param json_params [Hash]
|
41
|
+
# @param model [Class<ActiveRecord::Base>]
|
42
|
+
# @param params [Hash]
|
43
|
+
# @param current_ability [CanCan::Ability]
|
44
|
+
# @param models_index [Hash]
|
45
|
+
# @return [void]
|
46
|
+
def assign_fields_params!(json_params, model, params, current_ability, models_index)
|
47
47
|
return if params[:fields].blank?
|
48
48
|
|
49
|
-
model = rel.is_a?(ActiveRecord::Relation) ? rel.klass : rel.class
|
50
|
-
|
51
49
|
params[:fields].each do |key, fields|
|
52
|
-
|
53
|
-
|
54
|
-
merge_fields_params!(json_params, key, fields, model)
|
55
|
-
end
|
56
|
-
end
|
50
|
+
fields_model = models_index[key]
|
57
51
|
|
58
|
-
|
59
|
-
model_name = model.name.underscore
|
52
|
+
next unless model
|
60
53
|
|
61
|
-
|
62
|
-
json_params.merge!(build_fields_hash(model, fields))
|
63
|
-
else
|
64
|
-
hash = find_key_in_params(json_params, key)
|
54
|
+
fields = fields.split(',') if fields.is_a?(String)
|
65
55
|
|
66
|
-
fields_hash =
|
56
|
+
fields_hash = fields_model == model ? json_params : find_key_in_params(json_params, key)
|
67
57
|
|
68
|
-
|
58
|
+
fields_hash.merge!(build_fields_hash(fields_model, fields, current_ability))
|
69
59
|
end
|
70
60
|
end
|
71
61
|
|
72
|
-
|
73
|
-
|
62
|
+
# @param model [Class<ActiveRecord::Base>]
|
63
|
+
# @param fields [Hash]
|
64
|
+
# @param current_ability [CanCan::Ability]
|
65
|
+
# @return [Hash]
|
66
|
+
def build_fields_hash(model, fields, current_ability)
|
67
|
+
return { 'methods' => fields } unless model
|
68
|
+
|
69
|
+
column_names = model.column_names.map(&:to_sym)
|
70
|
+
instance_methods = model.instance_methods
|
71
|
+
permitted_attributes = current_ability.permitted_attributes(:read, model)
|
72
|
+
is_permitted_all = column_names == permitted_attributes
|
73
|
+
|
74
74
|
fields_hash = { 'only' => [], 'methods' => [] }
|
75
75
|
|
76
76
|
fields.each_with_object(fields_hash) do |field, acc|
|
77
|
-
|
77
|
+
field_symbol = field.to_sym
|
78
|
+
|
79
|
+
next if !is_permitted_all && permitted_attributes.exclude?(field_symbol)
|
80
|
+
|
81
|
+
if column_names.include?(field_symbol)
|
78
82
|
acc['only'] << field
|
79
|
-
elsif
|
83
|
+
elsif instance_methods.include?(field_symbol)
|
80
84
|
acc['methods'] << field
|
81
85
|
end
|
82
86
|
end
|
83
87
|
end
|
84
88
|
|
89
|
+
# @param params [Hash]
|
90
|
+
# @param key [String]
|
91
|
+
# @return [Hash]
|
85
92
|
def find_key_in_params(params, key)
|
86
93
|
params = params['include']
|
87
94
|
|
@@ -93,6 +100,8 @@ module Motor
|
|
93
100
|
end
|
94
101
|
end
|
95
102
|
|
103
|
+
# @param params [Hash]
|
104
|
+
# @return [Hash]
|
96
105
|
def normalize_include_params(params)
|
97
106
|
case params
|
98
107
|
when Array
|
@@ -112,6 +121,51 @@ module Motor
|
|
112
121
|
raise ArgumentError, "Wrong include param type #{params.class}"
|
113
122
|
end
|
114
123
|
end
|
124
|
+
|
125
|
+
# @param model [Class<ActiveRecord::Base>]
|
126
|
+
# @param includes_hash [Hash]
|
127
|
+
# @return [Hash]
|
128
|
+
def build_models_index(model, includes_hash)
|
129
|
+
default_index = {
|
130
|
+
model.name.underscore => model,
|
131
|
+
model.name.underscore.split('/').last => model
|
132
|
+
}
|
133
|
+
|
134
|
+
includes_hash.reduce(default_index) do |acc, (key, value)|
|
135
|
+
reflection = model.reflections[key]
|
136
|
+
|
137
|
+
next acc unless reflection
|
138
|
+
next acc if reflection.polymorphic?
|
139
|
+
|
140
|
+
acc[key] = reflection.klass
|
141
|
+
|
142
|
+
acc.merge(build_models_index(reflection.klass, value))
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# @param string_path [String]
|
147
|
+
# @return [Hash]
|
148
|
+
def build_hash_from_string_path(string_path)
|
149
|
+
string_path.split(',').reduce({}) do |accumulator, path|
|
150
|
+
hash = {}
|
151
|
+
|
152
|
+
path.split('.').reduce(hash) do |acc, part|
|
153
|
+
acc_hash = {}
|
154
|
+
|
155
|
+
acc[part] = acc_hash
|
156
|
+
|
157
|
+
acc_hash
|
158
|
+
end
|
159
|
+
|
160
|
+
accumulator.deep_merge(hash)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# @param params [Hash]
|
165
|
+
# @return [Boolean]
|
166
|
+
def limit_zero_params?(params)
|
167
|
+
params.dig(:page, :limit).yield_self { |limit| limit.present? && limit.to_i.zero? }
|
168
|
+
end
|
115
169
|
end
|
116
170
|
end
|
117
171
|
end
|
@@ -57,6 +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
|
+
next if column.respond_to?(:array?) && column.array?
|
60
61
|
next if model.validators_on(column.name).any?(ActiveModel::Validations::InclusionValidator)
|
61
62
|
|
62
63
|
column.name
|
data/lib/motor/assets.rb
CHANGED
@@ -8,10 +8,19 @@ module Motor
|
|
8
8
|
MANIFEST_PATH = ASSETS_PATH.join('manifest.json')
|
9
9
|
DEV_SERVER_URL = 'http://localhost:9090/'
|
10
10
|
|
11
|
+
CACHE_STORE =
|
12
|
+
if Rails.env.production?
|
13
|
+
ActiveSupport::Cache::MemoryStore.new(size: 5.megabytes)
|
14
|
+
else
|
15
|
+
ActiveSupport::Cache::NullStore.new
|
16
|
+
end
|
17
|
+
|
11
18
|
module_function
|
12
19
|
|
13
20
|
def manifest
|
14
|
-
|
21
|
+
CACHE_STORE.fetch('manifest') do
|
22
|
+
JSON.parse(MANIFEST_PATH.read)
|
23
|
+
end
|
15
24
|
end
|
16
25
|
|
17
26
|
def icons
|
data/lib/motor/build_schema.rb
CHANGED
@@ -58,9 +58,10 @@ module Motor
|
|
58
58
|
|
59
59
|
module_function
|
60
60
|
|
61
|
-
def call(cache_keys = {})
|
61
|
+
def call(cache_keys = {}, current_ability = nil)
|
62
62
|
schema = LoadFromRails.call
|
63
63
|
schema = MergeSchemaConfigs.call(schema, cache_keys)
|
64
|
+
schema = ApplyPermissions.call(schema, current_ability) if current_ability
|
64
65
|
|
65
66
|
ReorderSchema.call(schema, cache_keys)
|
66
67
|
end
|
@@ -75,4 +76,5 @@ require_relative './build_schema/find_icon'
|
|
75
76
|
require_relative './build_schema/persist_resource_configs'
|
76
77
|
require_relative './build_schema/reorder_schema'
|
77
78
|
require_relative './build_schema/merge_schema_configs'
|
79
|
+
require_relative './build_schema/apply_permissions'
|
78
80
|
require_relative './build_schema/utils'
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Motor
|
4
|
+
module BuildSchema
|
5
|
+
module ApplyPermissions
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def call(schema, ability)
|
9
|
+
schema.map do |model|
|
10
|
+
klass = model[:class_name].constantize
|
11
|
+
|
12
|
+
next unless ability.can?(:read, klass)
|
13
|
+
|
14
|
+
model[:associations] = filter_associations(model[:associations], ability)
|
15
|
+
model[:columns] = filter_columns(klass, model[:columns], ability)
|
16
|
+
model[:actions] = filter_actions(klass, model[:actions], ability)
|
17
|
+
|
18
|
+
model
|
19
|
+
end.compact
|
20
|
+
end
|
21
|
+
|
22
|
+
def filter_associations(associations, ability)
|
23
|
+
associations.select do |assoc|
|
24
|
+
ability.can?(:read, assoc[:model_name].classify.constantize)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def filter_columns(model, columns, ability)
|
29
|
+
columns.map do |column|
|
30
|
+
next unless ability.can?(:read, model, column[:name])
|
31
|
+
|
32
|
+
next if column.dig(:reference, :model_name).present? &&
|
33
|
+
!ability.can?(:read, column[:reference][:model_name].classify.constantize)
|
34
|
+
|
35
|
+
unless ability.can?(:update, model, column[:name])
|
36
|
+
column = column.merge(access_type: BuildSchema::ColumnAccessTypes::READ_ONLY)
|
37
|
+
end
|
38
|
+
|
39
|
+
column
|
40
|
+
end.compact
|
41
|
+
end
|
42
|
+
|
43
|
+
def filter_actions(model, actions, ability)
|
44
|
+
actions.select do |action|
|
45
|
+
ability.can?(action[:name].to_sym, model)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -35,6 +35,7 @@ module Motor
|
|
35
35
|
'token' => 'key',
|
36
36
|
'secret' => 'lock',
|
37
37
|
'automation' => 'manual-gearbox',
|
38
|
+
'workflow' => 'manual-gearbox',
|
38
39
|
'relationship' => 'hierarchy',
|
39
40
|
'person' => 'user',
|
40
41
|
'people' => 'users',
|
@@ -96,6 +97,8 @@ module Motor
|
|
96
97
|
'page' => 'brand-pagekit',
|
97
98
|
'date' => 'calendar-event',
|
98
99
|
'customer' => 'users',
|
100
|
+
'client' => 'users',
|
101
|
+
'ticket' => 'ticket',
|
99
102
|
'contact' => 'users',
|
100
103
|
'member' => 'users',
|
101
104
|
'admin' => 'user-check',
|
@@ -107,7 +110,8 @@ module Motor
|
|
107
110
|
'product' => 'building-store',
|
108
111
|
'html' => 'code',
|
109
112
|
'stripe' => 'brand-stripe',
|
110
|
-
'email' => 'mail'
|
113
|
+
'email' => 'mail',
|
114
|
+
'status' => 'hash'
|
111
115
|
}.freeze
|
112
116
|
|
113
117
|
DEFAULT_ICON = 'database'
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Motor
|
4
|
+
module CancanUtils
|
5
|
+
module AbilityPatch
|
6
|
+
def serialized_rules
|
7
|
+
@rules.map do |rule|
|
8
|
+
{
|
9
|
+
base_behavior: rule.base_behavior,
|
10
|
+
actions: expand_actions(rule.actions),
|
11
|
+
subjects: rule.subjects.map(&:to_s),
|
12
|
+
attributes: rule.attributes,
|
13
|
+
conditions: rule.conditions.as_json
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def rules_hash
|
19
|
+
serialized_rules.hash
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def default_alias_actions
|
25
|
+
super.merge(destroy: %i[remove delete])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -12,57 +12,67 @@ module Motor
|
|
12
12
|
|
13
13
|
module_function
|
14
14
|
|
15
|
-
def call(current_user = nil)
|
15
|
+
def call(current_user = nil, current_ability = nil)
|
16
16
|
cache_keys = LoadFromCache.load_cache_keys
|
17
17
|
|
18
18
|
CACHE_STORE.fetch("#{cache_keys.hash}#{current_user&.id}") do
|
19
19
|
CACHE_STORE.clear
|
20
20
|
|
21
|
-
|
21
|
+
data = build_data(cache_keys, current_user, current_ability)
|
22
|
+
Motor::ApplicationController.helpers.tag.div('', id: 'app', data: data)
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
25
26
|
# @return [Hash]
|
26
|
-
def build_data(cache_keys = {}, current_user = nil)
|
27
|
+
def build_data(cache_keys = {}, current_user = nil, current_ability = nil)
|
27
28
|
{
|
28
29
|
current_user: current_user&.as_json(only: %i[id email]),
|
30
|
+
current_rules: current_ability.serialized_rules,
|
29
31
|
audits_count: Motor::Audit.count,
|
30
32
|
base_path: Motor::Admin.routes.url_helpers.motor_path,
|
31
|
-
schema: Motor::BuildSchema.call(cache_keys),
|
33
|
+
schema: Motor::BuildSchema.call(cache_keys, current_ability),
|
32
34
|
header_links: header_links_data_hash(cache_keys[:configs]),
|
33
|
-
queries: queries_data_hash(cache_keys
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
queries: queries_data_hash(build_cache_key(cache_keys, :queries, current_user, current_ability),
|
36
|
+
current_ability),
|
37
|
+
dashboards: dashboards_data_hash(build_cache_key(cache_keys, :dashboards, current_user, current_ability),
|
38
|
+
current_ability),
|
39
|
+
alerts: alerts_data_hash(build_cache_key(cache_keys, :alerts, current_user, current_ability),
|
40
|
+
current_ability),
|
41
|
+
forms: forms_data_hash(build_cache_key(cache_keys, :forms, current_user, current_ability), current_ability)
|
37
42
|
}
|
38
43
|
end
|
39
44
|
|
45
|
+
# @return [String]
|
46
|
+
def build_cache_key(cache_keys, key, current_user, current_ability)
|
47
|
+
"#{cache_keys[key].hash}#{current_user&.id}#{current_ability&.rules_hash}"
|
48
|
+
end
|
49
|
+
|
40
50
|
def header_links_data_hash(cache_key = nil)
|
41
51
|
configs = Motor::Configs::LoadFromCache.load_configs(cache_key: cache_key)
|
42
52
|
|
43
53
|
configs.find { |c| c.key == 'header.links' }&.value || []
|
44
54
|
end
|
45
55
|
|
46
|
-
def queries_data_hash(cache_key = nil)
|
47
|
-
Motor::Configs::LoadFromCache.load_queries(cache_key: cache_key)
|
56
|
+
def queries_data_hash(cache_key = nil, current_ability = nil)
|
57
|
+
Motor::Configs::LoadFromCache.load_queries(cache_key: cache_key, current_ability: current_ability)
|
48
58
|
.as_json(only: %i[id name updated_at],
|
49
59
|
include: { tags: { only: %i[id name] } })
|
50
60
|
end
|
51
61
|
|
52
|
-
def dashboards_data_hash(cache_key = nil)
|
53
|
-
Motor::Configs::LoadFromCache.load_dashboards(cache_key: cache_key)
|
62
|
+
def dashboards_data_hash(cache_key = nil, current_ability = nil)
|
63
|
+
Motor::Configs::LoadFromCache.load_dashboards(cache_key: cache_key, current_ability: current_ability)
|
54
64
|
.as_json(only: %i[id title updated_at],
|
55
65
|
include: { tags: { only: %i[id name] } })
|
56
66
|
end
|
57
67
|
|
58
|
-
def alerts_data_hash(cache_key = nil)
|
59
|
-
Motor::Configs::LoadFromCache.load_alerts(cache_key: cache_key)
|
68
|
+
def alerts_data_hash(cache_key = nil, current_ability = nil)
|
69
|
+
Motor::Configs::LoadFromCache.load_alerts(cache_key: cache_key, current_ability: current_ability)
|
60
70
|
.as_json(only: %i[id name is_enabled updated_at],
|
61
71
|
include: { tags: { only: %i[id name] } })
|
62
72
|
end
|
63
73
|
|
64
|
-
def forms_data_hash(cache_key = nil)
|
65
|
-
Motor::Configs::LoadFromCache.load_forms(cache_key: cache_key)
|
74
|
+
def forms_data_hash(cache_key = nil, current_ability = nil)
|
75
|
+
Motor::Configs::LoadFromCache.load_forms(cache_key: cache_key, current_ability: current_ability)
|
66
76
|
.as_json(only: %i[id name updated_at],
|
67
77
|
include: { tags: { only: %i[id name] } })
|
68
78
|
end
|
@@ -32,27 +32,39 @@ module Motor
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
def load_queries(cache_key: nil)
|
35
|
+
def load_queries(cache_key: nil, current_ability: nil)
|
36
36
|
maybe_fetch_from_cache('queries', cache_key) do
|
37
|
-
Motor::Query.all.active.preload(:tags)
|
37
|
+
rel = Motor::Query.all.active.preload(:tags)
|
38
|
+
rel = rel.accessible_by(current_ability) if current_ability
|
39
|
+
|
40
|
+
rel.load
|
38
41
|
end
|
39
42
|
end
|
40
43
|
|
41
|
-
def load_dashboards(cache_key: nil)
|
44
|
+
def load_dashboards(cache_key: nil, current_ability: nil)
|
42
45
|
maybe_fetch_from_cache('dashboards', cache_key) do
|
43
|
-
Motor::Dashboard.all.active.preload(:tags)
|
46
|
+
rel = Motor::Dashboard.all.active.preload(:tags)
|
47
|
+
rel = rel.accessible_by(current_ability) if current_ability
|
48
|
+
|
49
|
+
rel.load
|
44
50
|
end
|
45
51
|
end
|
46
52
|
|
47
|
-
def load_alerts(cache_key: nil)
|
53
|
+
def load_alerts(cache_key: nil, current_ability: nil)
|
48
54
|
maybe_fetch_from_cache('alerts', cache_key) do
|
49
|
-
Motor::Alert.all.active.preload(:tags)
|
55
|
+
rel = Motor::Alert.all.active.preload(:tags)
|
56
|
+
rel = rel.accessible_by(current_ability) if current_ability
|
57
|
+
|
58
|
+
rel.load
|
50
59
|
end
|
51
60
|
end
|
52
61
|
|
53
|
-
def load_forms(cache_key: nil)
|
62
|
+
def load_forms(cache_key: nil, current_ability: nil)
|
54
63
|
maybe_fetch_from_cache('forms', cache_key) do
|
55
|
-
Motor::Form.all.active.preload(:tags)
|
64
|
+
rel = Motor::Form.all.active.preload(:tags)
|
65
|
+
rel = rel.accessible_by(current_ability) if current_ability
|
66
|
+
|
67
|
+
rel.load
|
56
68
|
end
|
57
69
|
end
|
58
70
|
|
@@ -16,6 +16,8 @@ module Motor
|
|
16
16
|
|
17
17
|
PG_ERROR_REGEXP = /\APG.+ERROR:/.freeze
|
18
18
|
|
19
|
+
RESERVED_VARIABLES = %w[current_user_id current_user_email].freeze
|
20
|
+
|
19
21
|
module_function
|
20
22
|
|
21
23
|
# @param query [Motor::Query]
|
@@ -110,11 +112,13 @@ module Motor
|
|
110
112
|
end
|
111
113
|
|
112
114
|
# @param variable_configs [Array<Hash>]
|
113
|
-
# @param
|
115
|
+
# @param variables_hash [Hash]
|
114
116
|
# @return [Hash]
|
115
117
|
def merge_variable_default_values(variable_configs, variables_hash)
|
116
|
-
variable_configs.each_with_object(
|
117
|
-
|
118
|
+
variable_configs.each_with_object(variables_hash.slice(*RESERVED_VARIABLES)) do |variable, acc|
|
119
|
+
next if RESERVED_VARIABLES.include?(variable[:name])
|
120
|
+
|
121
|
+
acc[variable[:name]] ||= variables_hash[variable[:name]] || variable[:default_value]
|
118
122
|
end
|
119
123
|
end
|
120
124
|
end
|
data/lib/motor/version.rb
CHANGED
Binary file
|
Binary file
|
data/ui/dist/manifest.json
CHANGED
@@ -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-
|
2072
|
-
"main-
|
2073
|
-
"main-
|
2074
|
-
"main.css": "main-
|
2075
|
-
"main.js": "main-
|
2071
|
+
"main-96c4a62d2fb789ab1080.css.gz": "main-96c4a62d2fb789ab1080.css.gz",
|
2072
|
+
"main-96c4a62d2fb789ab1080.js.LICENSE.txt": "main-96c4a62d2fb789ab1080.js.LICENSE.txt",
|
2073
|
+
"main-96c4a62d2fb789ab1080.js.gz": "main-96c4a62d2fb789ab1080.js.gz",
|
2074
|
+
"main.css": "main-96c4a62d2fb789ab1080.css",
|
2075
|
+
"main.js": "main-96c4a62d2fb789ab1080.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.
|
4
|
+
version: 0.1.60
|
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-
|
11
|
+
date: 2021-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord-filter
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '5.0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '5.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: cancancan
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -121,6 +121,7 @@ files:
|
|
121
121
|
- LICENSE
|
122
122
|
- README.md
|
123
123
|
- Rakefile
|
124
|
+
- app/controllers/concerns/motor/current_ability.rb
|
124
125
|
- app/controllers/concerns/motor/current_user_method.rb
|
125
126
|
- app/controllers/concerns/motor/load_and_authorize_dynamic_resource.rb
|
126
127
|
- app/controllers/concerns/motor/wrap_io_params.rb
|
@@ -130,6 +131,7 @@ files:
|
|
130
131
|
- app/controllers/motor/application_controller.rb
|
131
132
|
- app/controllers/motor/assets_controller.rb
|
132
133
|
- app/controllers/motor/audits_controller.rb
|
134
|
+
- app/controllers/motor/auth_tokens_controller.rb
|
133
135
|
- app/controllers/motor/configs_controller.rb
|
134
136
|
- app/controllers/motor/dashboards_controller.rb
|
135
137
|
- app/controllers/motor/data_controller.rb
|
@@ -139,7 +141,6 @@ files:
|
|
139
141
|
- app/controllers/motor/resource_methods_controller.rb
|
140
142
|
- app/controllers/motor/resources_controller.rb
|
141
143
|
- app/controllers/motor/run_queries_controller.rb
|
142
|
-
- app/controllers/motor/schemas_controller.rb
|
143
144
|
- app/controllers/motor/send_alerts_controller.rb
|
144
145
|
- app/controllers/motor/tags_controller.rb
|
145
146
|
- app/controllers/motor/ui_controller.rb
|
@@ -191,6 +192,7 @@ files:
|
|
191
192
|
- lib/motor/build_schema.rb
|
192
193
|
- lib/motor/build_schema/active_storage_attachment_schema.rb
|
193
194
|
- lib/motor/build_schema/adjust_devise_model_schema.rb
|
195
|
+
- lib/motor/build_schema/apply_permissions.rb
|
194
196
|
- lib/motor/build_schema/find_display_column.rb
|
195
197
|
- lib/motor/build_schema/find_icon.rb
|
196
198
|
- lib/motor/build_schema/load_from_rails.rb
|
@@ -198,6 +200,9 @@ files:
|
|
198
200
|
- lib/motor/build_schema/persist_resource_configs.rb
|
199
201
|
- lib/motor/build_schema/reorder_schema.rb
|
200
202
|
- lib/motor/build_schema/utils.rb
|
203
|
+
- lib/motor/cancan_utils.rb
|
204
|
+
- lib/motor/cancan_utils/ability_patch.rb
|
205
|
+
- lib/motor/cancan_utils/can_manage_all.rb
|
201
206
|
- lib/motor/configs.rb
|
202
207
|
- lib/motor/configs/build_configs_hash.rb
|
203
208
|
- lib/motor/configs/build_ui_app_tag.rb
|
@@ -1485,8 +1490,8 @@ files:
|
|
1485
1490
|
- ui/dist/icons/zoom-money.svg.gz
|
1486
1491
|
- ui/dist/icons/zoom-out.svg.gz
|
1487
1492
|
- ui/dist/icons/zoom-question.svg.gz
|
1488
|
-
- ui/dist/main-
|
1489
|
-
- ui/dist/main-
|
1493
|
+
- ui/dist/main-96c4a62d2fb789ab1080.css.gz
|
1494
|
+
- ui/dist/main-96c4a62d2fb789ab1080.js.gz
|
1490
1495
|
- ui/dist/manifest.json
|
1491
1496
|
homepage:
|
1492
1497
|
licenses:
|
Binary file
|