avo 0.2.3 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of avo might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Gemfile +52 -48
- data/Gemfile.lock +26 -2
- data/README.md +30 -9
- data/app/controllers/avo/application_controller.rb +34 -1
- data/app/controllers/avo/filters_controller.rb +19 -0
- data/app/controllers/avo/relations_controller.rb +34 -0
- data/app/controllers/avo/resource_overview_controller.rb +15 -7
- data/app/controllers/avo/resources_controller.rb +71 -145
- data/app/controllers/avo/search_controller.rb +55 -0
- data/app/helpers/avo/application_helper.rb +6 -2
- data/app/views/layouts/avo/_javascript.html.erb +3 -0
- data/app/views/layouts/avo/_translations.html.erb +5 -0
- data/app/views/layouts/avo/application.html.erb +40 -18
- data/avo.gemspec +5 -2
- data/config/credentials.yml.enc +1 -0
- data/config/routes.rb +11 -7
- data/lib/avo.rb +4 -0
- data/lib/avo/app/action.rb +8 -5
- data/lib/avo/app/app.rb +35 -28
- data/lib/avo/app/fields/belongs_to.rb +2 -2
- data/lib/avo/app/fields/code_field.rb +2 -0
- data/lib/avo/app/fields/country_field.rb +1 -1
- data/lib/avo/app/fields/field.rb +3 -1
- data/lib/avo/app/fields/field_extensions/visible_in_different_views.rb +4 -0
- data/lib/avo/app/fields/has_and_belongs_to_many.rb +1 -0
- data/lib/avo/app/fields/has_many.rb +1 -0
- data/lib/avo/app/fields/has_one.rb +2 -2
- data/lib/avo/app/fields/id_field.rb +4 -4
- data/lib/avo/app/fields/markdown_field.rb +27 -0
- data/lib/avo/app/fields/password_field.rb +3 -1
- data/lib/avo/app/fields/select_field.rb +1 -1
- data/lib/avo/app/licensing/community_license.rb +4 -0
- data/lib/avo/app/licensing/hq.rb +86 -0
- data/lib/avo/app/licensing/license.rb +48 -0
- data/lib/avo/app/licensing/license_manager.rb +25 -0
- data/lib/avo/app/licensing/null_license.rb +12 -0
- data/lib/avo/app/licensing/pro_license.rb +9 -0
- data/lib/avo/app/resource.rb +49 -18
- data/lib/avo/app/services/authorization_service.rb +40 -0
- data/lib/avo/configuration.rb +28 -2
- data/lib/avo/engine.rb +7 -7
- data/lib/avo/version.rb +1 -1
- data/lib/generators/avo/install_generator.rb +2 -1
- data/lib/generators/avo/templates/{initializer.rb → initializer/avo.rb} +2 -0
- data/lib/generators/avo/templates/locales/avo.en.yml +60 -0
- data/lib/generators/avo/templates/views/_scripts.html.erb +0 -0
- data/public/avo-packs/css/application-2f609d81.css +3 -0
- data/public/avo-packs/css/application-2f609d81.css.br +0 -0
- data/public/avo-packs/css/application-2f609d81.css.gz +0 -0
- data/public/avo-packs/js/application-84e2d573c3c15df1fb7b.js +3 -0
- data/public/avo-packs/js/{application-9a0dde96ad9918852965.js.LICENSE.txt → application-84e2d573c3c15df1fb7b.js.LICENSE.txt} +0 -0
- data/public/avo-packs/js/application-84e2d573c3c15df1fb7b.js.br +0 -0
- data/public/avo-packs/js/application-84e2d573c3c15df1fb7b.js.gz +0 -0
- data/public/avo-packs/js/application-84e2d573c3c15df1fb7b.js.map +1 -0
- data/public/avo-packs/js/application-84e2d573c3c15df1fb7b.js.map.br +0 -0
- data/public/avo-packs/js/application-84e2d573c3c15df1fb7b.js.map.gz +0 -0
- data/public/avo-packs/manifest.json +13 -6
- data/public/avo-packs/manifest.json.br +0 -0
- data/public/avo-packs/manifest.json.gz +0 -0
- data/public/avo-packs/media/font/fontello-068ca2b3.ttf +0 -0
- data/public/avo-packs/media/font/fontello-068ca2b3.ttf.br +0 -0
- data/public/avo-packs/media/font/fontello-068ca2b3.ttf.gz +0 -0
- data/public/avo-packs/media/font/fontello-8d4a4e6f.woff2 +0 -0
- data/public/avo-packs/media/font/fontello-9354499c.svg +72 -0
- data/public/avo-packs/media/font/fontello-9354499c.svg.br +0 -0
- data/public/avo-packs/media/font/fontello-9354499c.svg.gz +0 -0
- data/public/avo-packs/media/font/fontello-a782baa8.woff +0 -0
- data/public/avo-packs/media/font/fontello-e73a0647.eot +0 -0
- data/public/avo-packs/media/font/fontello-e73a0647.eot.br +0 -0
- data/public/avo-packs/media/font/fontello-e73a0647.eot.gz +0 -0
- data/public/avo-packs/media/svgs/arrow-circle-right-1ad1e15ec9a7aa54b67d126566a5aa2d.svg +1 -0
- data/public/avo-packs/media/svgs/arrow-circle-right-1ad1e15ec9a7aa54b67d126566a5aa2d.svg.br +0 -0
- data/public/avo-packs/media/svgs/arrow-circle-right-1ad1e15ec9a7aa54b67d126566a5aa2d.svg.gz +0 -0
- data/public/avo-packs/media/svgs/exclamation-8d1c0baa390a8df9bb52176011eb5892.svg +1 -0
- data/public/avo-packs/media/svgs/exclamation-8d1c0baa390a8df9bb52176011eb5892.svg.br +0 -0
- data/public/avo-packs/media/svgs/exclamation-8d1c0baa390a8df9bb52176011eb5892.svg.gz +0 -0
- metadata +90 -22
- data/public/avo-packs/css/application-5dc4dd78.css +0 -3
- data/public/avo-packs/css/application-5dc4dd78.css.br +0 -0
- data/public/avo-packs/css/application-5dc4dd78.css.gz +0 -0
- data/public/avo-packs/js/application-9a0dde96ad9918852965.js +0 -3
- data/public/avo-packs/js/application-9a0dde96ad9918852965.js.br +0 -0
- data/public/avo-packs/js/application-9a0dde96ad9918852965.js.gz +0 -0
- data/public/avo-packs/js/application-9a0dde96ad9918852965.js.map +0 -1
- data/public/avo-packs/js/application-9a0dde96ad9918852965.js.map.br +0 -0
- data/public/avo-packs/js/application-9a0dde96ad9918852965.js.map.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: 12b4c2f7a1b63d7296ac6f9b8edb5f133884ca5b10d1ed5c5a85e230364dad07
|
4
|
+
data.tar.gz: 5dd72ab388c40de38a1a36e3bf077360afabf0e75fe1922feec31f1cc9cd7913
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d2369b3f99c6244a3e0a4966cac220283f2f2bef7c99edbc31e56407f4a3100460691b663486a7bf96626eee5086861e3295f6e04f066cedff79c25f9b4927c5
|
7
|
+
data.tar.gz: d98ce0432dfa0157ea480f21bb028c65bc33e9e2a59e88731efbde478806dcae96a04524ce04993741778329bddaa7083a8be69b71bea4b1282b2219550e2b01
|
data/Gemfile
CHANGED
@@ -23,54 +23,51 @@ gem 'inline_svg'
|
|
23
23
|
gem 'countries'
|
24
24
|
|
25
25
|
# Authorization
|
26
|
-
gem
|
27
|
-
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
gem 'ruby-debug-ide', require: false
|
72
|
-
gem 'debase'
|
73
|
-
end
|
26
|
+
gem 'pundit'
|
27
|
+
|
28
|
+
# Dependencies for dummy_app
|
29
|
+
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
|
30
|
+
gem 'rails', '~> 6.0.2', '>= 6.0.2.2'
|
31
|
+
# Use postgresql as the database for Active Record
|
32
|
+
gem 'pg', '>= 0.18', '< 2.0'
|
33
|
+
# Use Puma as the app server
|
34
|
+
gem 'puma', '~> 4.3.5'
|
35
|
+
# Use SCSS for stylesheets
|
36
|
+
gem 'sass-rails', '>= 6'
|
37
|
+
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
|
38
|
+
# gem 'turbolinks', '~> 5'
|
39
|
+
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
|
40
|
+
gem 'jbuilder', '~> 2.7'
|
41
|
+
# Use Redis adapter to run Action Cable in production
|
42
|
+
# gem 'redis', '~> 4.0'
|
43
|
+
# Use Active Model has_secure_password
|
44
|
+
# gem 'bcrypt', '~> 3.1.7'
|
45
|
+
|
46
|
+
# Use Active Storage variant
|
47
|
+
# gem 'image_processing', '~> 1.2'
|
48
|
+
|
49
|
+
# Reduces boot times through caching; required in config/boot.rb
|
50
|
+
gem 'bootsnap', '>= 1.4.2', require: false
|
51
|
+
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
|
52
|
+
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
|
53
|
+
gem 'dotenv-rails'
|
54
|
+
# Access an interactive console on exception pages or by calling 'console' anywhere in the code.
|
55
|
+
gem 'web-console', '>= 3.3.0'
|
56
|
+
gem 'listen', '>= 3.0.5', '< 3.2'
|
57
|
+
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
|
58
|
+
gem 'spring'
|
59
|
+
gem 'spring-watcher-listen', '~> 2.0.0'
|
60
|
+
|
61
|
+
gem 'factory_bot_rails'
|
62
|
+
gem 'faker', require: false
|
63
|
+
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
64
|
+
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
|
65
|
+
|
66
|
+
gem 'devise'
|
67
|
+
gem 'database_cleaner'
|
68
|
+
|
69
|
+
gem 'ruby-debug-ide', require: false
|
70
|
+
gem 'debase'
|
74
71
|
|
75
72
|
group :development, :test do
|
76
73
|
gem 'rspec-rails', '~> 4.0.0'
|
@@ -83,6 +80,7 @@ group :development, :test do
|
|
83
80
|
gem 'rubocop'
|
84
81
|
gem 'simplecov', require: false
|
85
82
|
gem 'simplecov-cobertura'
|
83
|
+
gem 'webmock'
|
86
84
|
|
87
85
|
# Release helper
|
88
86
|
gem 'bump', require: false
|
@@ -93,3 +91,9 @@ gem 'zeitwerk', '~> 2.3'
|
|
93
91
|
|
94
92
|
# Pagination
|
95
93
|
gem 'kaminari'
|
94
|
+
|
95
|
+
gem 'httparty'
|
96
|
+
|
97
|
+
gem 'iso'
|
98
|
+
|
99
|
+
gem 'i18n-js'
|
data/Gemfile.lock
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
avo (0.
|
4
|
+
avo (0.4.1)
|
5
5
|
countries
|
6
|
+
httparty
|
7
|
+
i18n-js
|
6
8
|
inline_svg
|
7
9
|
kaminari
|
8
|
-
|
10
|
+
pundit
|
11
|
+
rails (>= 6.0)
|
9
12
|
webpacker
|
10
13
|
zeitwerk
|
11
14
|
|
@@ -91,6 +94,7 @@ GEM
|
|
91
94
|
i18n_data (~> 0.10.0)
|
92
95
|
sixarm_ruby_unaccent (~> 1.1)
|
93
96
|
unicode_utils (~> 1.4)
|
97
|
+
crack (0.4.4)
|
94
98
|
crass (1.0.6)
|
95
99
|
database_cleaner (1.8.5)
|
96
100
|
debase (0.2.4.1)
|
@@ -123,12 +127,20 @@ GEM
|
|
123
127
|
gem-release (2.1.1)
|
124
128
|
globalid (0.4.2)
|
125
129
|
activesupport (>= 4.2.0)
|
130
|
+
hashdiff (1.0.1)
|
131
|
+
httparty (0.18.1)
|
132
|
+
mime-types (~> 3.0)
|
133
|
+
multi_xml (>= 0.5.2)
|
126
134
|
i18n (1.8.5)
|
127
135
|
concurrent-ruby (~> 1.0)
|
136
|
+
i18n-js (3.8.0)
|
137
|
+
i18n (>= 0.6.6)
|
128
138
|
i18n_data (0.10.0)
|
129
139
|
inline_svg (1.7.1)
|
130
140
|
activesupport (>= 3.0)
|
131
141
|
nokogiri (>= 1.6)
|
142
|
+
iso (0.3.0)
|
143
|
+
i18n
|
132
144
|
jbuilder (2.10.1)
|
133
145
|
activesupport (>= 5.0.0)
|
134
146
|
kaminari (1.2.1)
|
@@ -155,11 +167,15 @@ GEM
|
|
155
167
|
marcel (0.3.3)
|
156
168
|
mimemagic (~> 0.3.2)
|
157
169
|
method_source (1.0.0)
|
170
|
+
mime-types (3.3.1)
|
171
|
+
mime-types-data (~> 3.2015)
|
172
|
+
mime-types-data (3.2020.0512)
|
158
173
|
mimemagic (0.3.5)
|
159
174
|
mini_mime (1.0.2)
|
160
175
|
mini_portile2 (2.4.0)
|
161
176
|
minitest (5.14.2)
|
162
177
|
msgpack (1.3.3)
|
178
|
+
multi_xml (0.6.0)
|
163
179
|
nio4r (2.5.4)
|
164
180
|
nokogiri (1.10.10)
|
165
181
|
mini_portile2 (~> 2.4.0)
|
@@ -296,6 +312,10 @@ GEM
|
|
296
312
|
nokogiri (~> 1.6)
|
297
313
|
rubyzip (>= 1.3.0)
|
298
314
|
selenium-webdriver (>= 3.0, < 4.0)
|
315
|
+
webmock (3.9.3)
|
316
|
+
addressable (>= 2.3.6)
|
317
|
+
crack (>= 0.3.2)
|
318
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
299
319
|
webpacker (4.3.0)
|
300
320
|
activesupport (>= 4.2)
|
301
321
|
rack-proxy (>= 0.6.1)
|
@@ -325,7 +345,10 @@ DEPENDENCIES
|
|
325
345
|
faker
|
326
346
|
fuubar
|
327
347
|
gem-release
|
348
|
+
httparty
|
349
|
+
i18n-js
|
328
350
|
inline_svg
|
351
|
+
iso
|
329
352
|
jbuilder (~> 2.7)
|
330
353
|
kaminari
|
331
354
|
listen (>= 3.0.5, < 3.2)
|
@@ -345,6 +368,7 @@ DEPENDENCIES
|
|
345
368
|
tzinfo-data
|
346
369
|
web-console (>= 3.3.0)
|
347
370
|
webdrivers
|
371
|
+
webmock
|
348
372
|
webpacker (~> 4.0)
|
349
373
|
zeitwerk (~> 2.3)
|
350
374
|
|
data/README.md
CHANGED
@@ -1,15 +1,41 @@
|
|
1
1
|
![Tests](https://github.com/avo-hq/avo/workflows/Tests/badge.svg)
|
2
2
|
![reviewdog](https://github.com/avo-hq/avo/workflows/reviewdog/badge.svg)
|
3
3
|
[![codecov](https://codecov.io/gh/avo-hq/avo/branch/master/graph/badge.svg?token=Q2LMFE4989)](https://codecov.io/gh/avo-hq/avo)
|
4
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/676a0afa2cc79f03aa29/maintainability)](https://codeclimate.com/github/avo-hq/avo/maintainability)
|
4
5
|
|
5
|
-
|
6
|
-
|
6
|
+
![](https://avohq.io/img/logo-full-stroke-tiny-2x.png)
|
7
|
+
|
8
|
+
**Configuration-based, no-maintenance, extendable Ruby on Rails admin**
|
7
9
|
|
8
10
|
Avo is a beautiful next-generation framework that empowers you, the developer, to create fantastic admin panels for your Ruby on Rails apps with the flexibility to fit your needs as you grow.
|
9
11
|
|
10
|
-
|
12
|
+
## Get started
|
13
|
+
|
14
|
+
**Website**: [avohq.io](https://avohq.io)\
|
15
|
+
**Documentation**: [docs.avohq.io](https://docs.avohq.io)\
|
16
|
+
**Twitter**: [avo_hq](https://twitter.com/avo_hq)\
|
17
|
+
**Community chat**: [discord](https://discord.gg/pkTF6y8)\
|
18
|
+
**Issue tracker**: [GitHub issues](http://github.com/avo-hq/avo/issues)
|
19
|
+
|
20
|
+
## Features
|
11
21
|
|
12
|
-
|
22
|
+
- **Code driven configuration** - Configure your Rails dashboard entirely by writing Ruby code.
|
23
|
+
- **Resource Management** - Create a CRUD interface for Active Record from one command. No more copy-pasting view and controller files around.
|
24
|
+
- **Active Storage support** - Amazingly easy, **one-line**, single or multi-file integration with **ActiveStorage**.
|
25
|
+
- **Grid view** - Beautiful card layout to showcase your content.
|
26
|
+
- **Actions** - Run custom actions to one or more of your resources with as little as pressing a button 💪
|
27
|
+
- **Filters** - Write your own custom filters to quickly segment your data.
|
28
|
+
- **Keeps your app clean** - You don't need to change your app to use Avo. Drop it in your existing app or add it to a new one and you're done 🙌
|
29
|
+
- **Custom fields***- No worries if we missed a field you need. Generate a custom field in a jiffy.
|
30
|
+
- **Dashboard widgets and metrics*** - Customize your dashboard with the tools and analytics you need.
|
31
|
+
- **Custom tools*** - You need to add a page with something completely new, you've got it!
|
32
|
+
- **Authorization** - Leverage Pundit policies to build a robust and scalable authorization system.
|
33
|
+
- **Themable*** - Dress it up into your own colors.
|
34
|
+
- **Localization*** - Have it available in any language you need.
|
35
|
+
|
36
|
+
*Some features are still under development
|
37
|
+
|
38
|
+
# Installation
|
13
39
|
Add this line to your application's `Gemfile`:
|
14
40
|
|
15
41
|
```ruby
|
@@ -20,8 +46,3 @@ And then execute:
|
|
20
46
|
```bash
|
21
47
|
$ bundle install
|
22
48
|
```
|
23
|
-
|
24
|
-
Website: [avohq.io](https://avohq.io)\
|
25
|
-
Docs: [docs.avohq.io](https://docs.avohq.io)\
|
26
|
-
Twitter: [avo_hq](https://twitter.com/avo_hq)\
|
27
|
-
Community: [discord](https://discord.gg/pkTF6y8)
|
@@ -5,7 +5,10 @@ module Avo
|
|
5
5
|
before_action :init_app
|
6
6
|
|
7
7
|
def init_app
|
8
|
-
Avo::App.
|
8
|
+
Avo::App.boot if Avo::IN_DEVELOPMENT
|
9
|
+
Avo::App.init request
|
10
|
+
|
11
|
+
@license = Avo::App.license
|
9
12
|
end
|
10
13
|
|
11
14
|
def exception_logger(exception)
|
@@ -20,6 +23,20 @@ module Avo
|
|
20
23
|
end
|
21
24
|
|
22
25
|
private
|
26
|
+
def resource
|
27
|
+
eager_load_files(resource_model).find params[:id]
|
28
|
+
end
|
29
|
+
|
30
|
+
def eager_load_files(query)
|
31
|
+
if avo_resource.attached_file_fields.present?
|
32
|
+
avo_resource.attached_file_fields.map(&:id).map do |field|
|
33
|
+
query = query.send :"with_attached_#{field}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
query
|
38
|
+
end
|
39
|
+
|
23
40
|
def resource_model
|
24
41
|
avo_resource.model
|
25
42
|
end
|
@@ -27,5 +44,21 @@ module Avo
|
|
27
44
|
def avo_resource
|
28
45
|
App.get_resource params[:resource_name].to_s.camelize.singularize
|
29
46
|
end
|
47
|
+
|
48
|
+
def authorize_user
|
49
|
+
return if params[:controller] == 'avo/search'
|
50
|
+
|
51
|
+
model = record = avo_resource.model
|
52
|
+
|
53
|
+
if ['show', 'edit', 'update'].include?(params[:action]) && params[:controller] == 'avo/resources'
|
54
|
+
record = resource
|
55
|
+
end
|
56
|
+
|
57
|
+
return render_unauthorized unless AuthorizationService::authorize_action current_user, record, params[:action]
|
58
|
+
end
|
59
|
+
|
60
|
+
def render_unauthorized
|
61
|
+
render json: { message: I18n.t('avo.unauthorized') }, status: 403
|
62
|
+
end
|
30
63
|
end
|
31
64
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_dependency 'avo/application_controller'
|
2
|
+
|
3
|
+
module Avo
|
4
|
+
class FiltersController < ApplicationController
|
5
|
+
before_action :authorize_user
|
6
|
+
|
7
|
+
def index
|
8
|
+
filters = []
|
9
|
+
|
10
|
+
avo_resource.get_filters.each do |filter|
|
11
|
+
filters.push(filter.new.render_response)
|
12
|
+
end
|
13
|
+
|
14
|
+
render json: {
|
15
|
+
filters: filters,
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require_dependency 'avo/application_controller'
|
2
|
+
|
3
|
+
module Avo
|
4
|
+
class RelationsController < ApplicationController
|
5
|
+
before_action :authorize_user
|
6
|
+
|
7
|
+
def attach
|
8
|
+
resource.send(params[:attachment_name]) << attachment_model
|
9
|
+
|
10
|
+
render json: {
|
11
|
+
success: true,
|
12
|
+
message: I18n.t('avo.attachment_class_attached', attachment_class: attachment_class),
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def detach
|
17
|
+
resource.send(params[:attachment_name]).delete attachment_model
|
18
|
+
|
19
|
+
render json: {
|
20
|
+
success: true,
|
21
|
+
message: I18n.t('avo.attachment_class_detached', attachment_class: attachment_class),
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def attachment_class
|
27
|
+
App.get_model_class_by_name params[:attachment_name].pluralize 1
|
28
|
+
end
|
29
|
+
|
30
|
+
def attachment_model
|
31
|
+
attachment_class.safe_constantize.find params[:attachment_id]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -3,13 +3,16 @@ require_dependency 'avo/application_controller'
|
|
3
3
|
module Avo
|
4
4
|
class ResourceOverviewController < ApplicationController
|
5
5
|
def index
|
6
|
-
resources = App.get_resources
|
7
|
-
{
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
resources = App.get_resources
|
7
|
+
.select { |resource| AuthorizationService::authorize session_user, resource.model, Avo.configuration.authorization_methods.stringify_keys['index'] }
|
8
|
+
.sort_by(&:name)
|
9
|
+
.map do |resource|
|
10
|
+
{
|
11
|
+
name: resource.name,
|
12
|
+
url: resource.url,
|
13
|
+
count: resource.model.count,
|
14
|
+
}
|
15
|
+
end
|
13
16
|
|
14
17
|
render json: {
|
15
18
|
resources: resources,
|
@@ -17,5 +20,10 @@ module Avo
|
|
17
20
|
hide_docs: Avo.configuration.hide_documentation_link,
|
18
21
|
}
|
19
22
|
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def session_user
|
26
|
+
current_user.present? ? current_user : nil
|
27
|
+
end
|
20
28
|
end
|
21
29
|
end
|
@@ -2,21 +2,26 @@ require_dependency 'avo/application_controller'
|
|
2
2
|
|
3
3
|
module Avo
|
4
4
|
class ResourcesController < ApplicationController
|
5
|
+
before_action :authorize_user
|
6
|
+
|
5
7
|
def index
|
6
8
|
params[:page] ||= 1
|
7
9
|
params[:per_page] ||= Avo.configuration.per_page
|
8
10
|
params[:sort_by] = params[:sort_by].present? ? params[:sort_by] : :created_at
|
9
11
|
params[:sort_direction] = params[:sort_direction].present? ? params[:sort_direction] : :desc
|
10
|
-
|
12
|
+
|
13
|
+
query = AuthorizationService.with_policy current_user, resource_model
|
11
14
|
|
12
15
|
if params[:via_resource_name].present? and params[:via_resource_id].present? and params[:via_relationship].present?
|
13
|
-
# get the
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
query =
|
16
|
+
# get the related resource (via_resource)
|
17
|
+
related_model = App.get_resource_by_name(params[:via_resource_name]).model
|
18
|
+
|
19
|
+
relation = related_model.find(params[:via_resource_id]).public_send(params[:via_relationship])
|
20
|
+
query = AuthorizationService.with_policy current_user, relation
|
21
|
+
|
18
22
|
params[:per_page] = Avo.configuration.via_per_page
|
19
23
|
elsif ['has_many', 'has_and_belongs_to_many'].include? params[:for_relation]
|
24
|
+
# has_many searchable query
|
20
25
|
resources = resource_model.all.map do |model|
|
21
26
|
{
|
22
27
|
value: model.id,
|
@@ -27,22 +32,18 @@ module Avo
|
|
27
32
|
return render json: {
|
28
33
|
resources: resources
|
29
34
|
}
|
30
|
-
else
|
31
|
-
query = resource_model
|
32
35
|
end
|
33
36
|
|
34
37
|
query = query.order("#{params[:sort_by]} #{params[:sort_direction]}")
|
35
38
|
|
36
|
-
|
37
|
-
|
38
|
-
query = filter_class.safe_constantize.new.apply_query request, query, filter_value
|
39
|
-
end
|
39
|
+
applied_filters.each do |filter_class, filter_value|
|
40
|
+
query = filter_class.safe_constantize.new.apply_query request, query, filter_value
|
40
41
|
end
|
41
42
|
|
42
43
|
# Eager load the attachments
|
43
44
|
query = eager_load_files(query)
|
44
45
|
|
45
|
-
# Eager
|
46
|
+
# Eager load the relations
|
46
47
|
if avo_resource.includes.present?
|
47
48
|
query = query.includes(*avo_resource.includes)
|
48
49
|
end
|
@@ -51,48 +52,21 @@ module Avo
|
|
51
52
|
|
52
53
|
resources_with_fields = []
|
53
54
|
resources.each do |resource|
|
54
|
-
resources_with_fields << Avo::Resources::Resource.hydrate_resource(resource, avo_resource, :index)
|
55
|
+
resources_with_fields << Avo::Resources::Resource.hydrate_resource(model: resource, resource: avo_resource, view: :index, user: current_user)
|
55
56
|
end
|
56
57
|
|
57
|
-
meta = {
|
58
|
-
per_page_steps: Avo.configuration.per_page_steps,
|
59
|
-
available_view_types: avo_resource.available_view_types,
|
60
|
-
default_view_type: avo_resource.default_view_type || Avo.configuration.default_view_type,
|
61
|
-
}
|
62
|
-
|
63
58
|
render json: {
|
64
59
|
success: true,
|
65
|
-
meta:
|
60
|
+
meta: build_meta,
|
66
61
|
resources: resources_with_fields,
|
67
62
|
per_page: params[:per_page],
|
68
63
|
total_pages: resources.total_pages,
|
69
64
|
}
|
70
65
|
end
|
71
66
|
|
72
|
-
def search
|
73
|
-
if params[:resource_name].present?
|
74
|
-
resources = add_link_to_search_results search_resource(avo_resource)
|
75
|
-
else
|
76
|
-
resources = []
|
77
|
-
|
78
|
-
resources_to_search_through = App.get_resources.select { |r| r.search.present? }
|
79
|
-
resources_to_search_through.each do |resource_model|
|
80
|
-
found_resources = add_link_to_search_results search_resource(resource_model)
|
81
|
-
resources.push({
|
82
|
-
label: resource_model.name,
|
83
|
-
resources: found_resources
|
84
|
-
})
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
render json: {
|
89
|
-
resources: resources
|
90
|
-
}
|
91
|
-
end
|
92
|
-
|
93
67
|
def show
|
94
68
|
render json: {
|
95
|
-
resource: Avo::Resources::Resource.hydrate_resource(resource, avo_resource, @view || :show),
|
69
|
+
resource: Avo::Resources::Resource.hydrate_resource(model: resource, resource: avo_resource, view: @view || :show, user: current_user),
|
96
70
|
}
|
97
71
|
end
|
98
72
|
|
@@ -120,8 +94,8 @@ module Avo
|
|
120
94
|
|
121
95
|
render json: {
|
122
96
|
success: true,
|
123
|
-
resource: Avo::Resources::Resource.hydrate_resource(resource, avo_resource, :show),
|
124
|
-
message: '
|
97
|
+
resource: Avo::Resources::Resource.hydrate_resource(model: resource, resource: avo_resource, view: :show, user: current_user),
|
98
|
+
message: I18n.t('avo.resource_updated'),
|
125
99
|
}
|
126
100
|
end
|
127
101
|
|
@@ -143,16 +117,14 @@ module Avo
|
|
143
117
|
|
144
118
|
render json: {
|
145
119
|
success: true,
|
146
|
-
resource: Avo::Resources::Resource.hydrate_resource(resource, avo_resource, :create),
|
147
|
-
message: '
|
120
|
+
resource: Avo::Resources::Resource.hydrate_resource(model: resource, resource: avo_resource, view: :create, user: current_user),
|
121
|
+
message: I18n.t('avo.resource_created'),
|
148
122
|
}
|
149
123
|
end
|
150
124
|
|
151
|
-
def
|
152
|
-
resource = resource_model.new
|
153
|
-
|
125
|
+
def new
|
154
126
|
render json: {
|
155
|
-
resource: Avo::Resources::Resource.hydrate_resource(
|
127
|
+
resource: Avo::Resources::Resource.hydrate_resource(model: resource_model.new, resource: avo_resource, view: :create, user: current_user),
|
156
128
|
}
|
157
129
|
end
|
158
130
|
|
@@ -160,68 +132,11 @@ module Avo
|
|
160
132
|
resource.destroy!
|
161
133
|
|
162
134
|
render json: {
|
163
|
-
message: '
|
135
|
+
message: I18n.t('avo.resource_destroyed'),
|
164
136
|
}
|
165
137
|
end
|
166
138
|
|
167
|
-
def filters
|
168
|
-
avo_filters = avo_resource.get_filters
|
169
|
-
filters = []
|
170
|
-
|
171
|
-
avo_filters.each do |filter|
|
172
|
-
filters.push(filter.new.render_response)
|
173
|
-
end
|
174
|
-
|
175
|
-
render json: {
|
176
|
-
filters: filters,
|
177
|
-
}
|
178
|
-
end
|
179
|
-
|
180
|
-
def attach
|
181
|
-
attachment_class = App.get_model_class_by_name params[:attachment_name].pluralize 1
|
182
|
-
attachment_model = attachment_class.safe_constantize.find params[:attachment_id]
|
183
|
-
attached = resource.send(params[:attachment_name]) << attachment_model
|
184
|
-
|
185
|
-
render json: {
|
186
|
-
success: true,
|
187
|
-
message: "#{attachment_class} attached.",
|
188
|
-
}
|
189
|
-
end
|
190
|
-
|
191
|
-
def detach
|
192
|
-
attachment_class = App.get_model_class_by_name params[:attachment_name].pluralize 1
|
193
|
-
attachment_model = attachment_class.safe_constantize.find params[:attachment_id]
|
194
|
-
attached = resource.send(params[:attachment_name]).delete attachment_model
|
195
|
-
|
196
|
-
render json: {
|
197
|
-
success: true,
|
198
|
-
message: "#{attachment_class} attached.",
|
199
|
-
}
|
200
|
-
end
|
201
|
-
|
202
|
-
def cast_nullable(params)
|
203
|
-
fields = avo_resource.get_fields
|
204
|
-
|
205
|
-
nullable_fields = fields.filter { |field| field.nullable }
|
206
|
-
.map { |field| [field.id, field.null_values] }
|
207
|
-
.to_h
|
208
|
-
|
209
|
-
params.each do |key, value|
|
210
|
-
nullable = nullable_fields[key.to_sym]
|
211
|
-
|
212
|
-
if nullable.present? && value.in?(nullable)
|
213
|
-
params[key] = nil
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
params
|
218
|
-
end
|
219
|
-
|
220
139
|
private
|
221
|
-
def resource
|
222
|
-
eager_load_files(resource_model).find params[:id]
|
223
|
-
end
|
224
|
-
|
225
140
|
def permitted_params
|
226
141
|
permitted = avo_resource.get_fields.select(&:updatable).map do |field|
|
227
142
|
# If it's a relation
|
@@ -250,41 +165,6 @@ module Avo
|
|
250
165
|
params.require(:resource).permit(permitted_params)
|
251
166
|
end
|
252
167
|
|
253
|
-
def search_resource(avo_resource)
|
254
|
-
avo_resource.query_search(query: params[:q], via_resource_name: params[:via_resource_name], via_resource_id: params[:via_resource_id])
|
255
|
-
end
|
256
|
-
|
257
|
-
def add_link_to_search_results(resources)
|
258
|
-
resources.map do |model|
|
259
|
-
resource = model.as_json
|
260
|
-
resource[:link] = "/resources/#{model.class.to_s.singularize.underscore}/#{model.id}"
|
261
|
-
|
262
|
-
resource
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
def eager_load_files(query)
|
267
|
-
if avo_resource.attached_file_fields.present?
|
268
|
-
avo_resource.attached_file_fields.map(&:id).map do |field|
|
269
|
-
query = query.send :"with_attached_#{field}"
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
query
|
274
|
-
end
|
275
|
-
|
276
|
-
def process_file_field(field, attachment)
|
277
|
-
if attachment.is_a? ActionDispatch::Http::UploadedFile
|
278
|
-
# New file has been attached
|
279
|
-
field.attach attachment
|
280
|
-
elsif attachment.blank?
|
281
|
-
# File has been deleted
|
282
|
-
field.purge
|
283
|
-
elsif attachment.is_a? String
|
284
|
-
# Field is unchanged
|
285
|
-
end
|
286
|
-
end
|
287
|
-
|
288
168
|
def update_file_fields
|
289
169
|
# Pick and attach file fields
|
290
170
|
attached_file_fields = avo_resource.attached_file_fields
|
@@ -322,7 +202,19 @@ module Avo
|
|
322
202
|
end
|
323
203
|
end
|
324
204
|
|
325
|
-
def
|
205
|
+
def process_file_field(field, attachment)
|
206
|
+
if attachment.is_a? ActionDispatch::Http::UploadedFile
|
207
|
+
# New file has been attached
|
208
|
+
field.attach attachment
|
209
|
+
elsif attachment.blank?
|
210
|
+
# File has been deleted
|
211
|
+
field.purge
|
212
|
+
elsif attachment.is_a? String
|
213
|
+
# Field is unchanged
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def applied_filters
|
326
218
|
if params[:filters].present?
|
327
219
|
return JSON.parse(Base64.decode64(params[:filters]))
|
328
220
|
end
|
@@ -339,5 +231,39 @@ module Avo
|
|
339
231
|
|
340
232
|
filter_defaults
|
341
233
|
end
|
234
|
+
|
235
|
+
def cast_nullable(params)
|
236
|
+
fields = avo_resource.get_fields
|
237
|
+
|
238
|
+
nullable_fields = fields.filter { |field| field.nullable }
|
239
|
+
.map { |field| [field.id, field.null_values] }
|
240
|
+
.to_h
|
241
|
+
|
242
|
+
params.each do |key, value|
|
243
|
+
nullable = nullable_fields[key.to_sym]
|
244
|
+
|
245
|
+
if nullable.present? && value.in?(nullable)
|
246
|
+
params[key] = nil
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
params
|
251
|
+
end
|
252
|
+
|
253
|
+
def build_meta
|
254
|
+
{
|
255
|
+
per_page_steps: Avo.configuration.per_page_steps,
|
256
|
+
available_view_types: avo_resource.available_view_types,
|
257
|
+
default_view_type: avo_resource.default_view_type || Avo.configuration.default_view_type,
|
258
|
+
translation_key: avo_resource.translation_key,
|
259
|
+
authorization: {
|
260
|
+
create: AuthorizationService::authorize(current_user, avo_resource.model, Avo.configuration.authorization_methods.stringify_keys['create']),
|
261
|
+
edit: AuthorizationService::authorize(current_user, avo_resource.model, Avo.configuration.authorization_methods.stringify_keys['edit']),
|
262
|
+
update: AuthorizationService::authorize(current_user, avo_resource.model, Avo.configuration.authorization_methods.stringify_keys['update']),
|
263
|
+
show: AuthorizationService::authorize(current_user, avo_resource.model, Avo.configuration.authorization_methods.stringify_keys['show']),
|
264
|
+
destroy: AuthorizationService::authorize(current_user, avo_resource.model, Avo.configuration.authorization_methods.stringify_keys['destroy']),
|
265
|
+
},
|
266
|
+
}
|
267
|
+
end
|
342
268
|
end
|
343
269
|
end
|