avo 0.2.4 → 0.4.2

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.

Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +52 -48
  3. data/Gemfile.lock +25 -1
  4. data/README.md +5 -3
  5. data/app/controllers/avo/application_controller.rb +34 -1
  6. data/app/controllers/avo/filters_controller.rb +19 -0
  7. data/app/controllers/avo/relations_controller.rb +34 -0
  8. data/app/controllers/avo/resource_overview_controller.rb +15 -7
  9. data/app/controllers/avo/resources_controller.rb +71 -145
  10. data/app/controllers/avo/search_controller.rb +55 -0
  11. data/app/helpers/avo/application_helper.rb +6 -2
  12. data/app/views/layouts/avo/_javascript.html.erb +3 -0
  13. data/app/views/layouts/avo/_translations.html.erb +5 -0
  14. data/app/views/layouts/avo/application.html.erb +40 -18
  15. data/avo.gemspec +4 -1
  16. data/config/credentials.yml.enc +1 -0
  17. data/config/routes.rb +11 -7
  18. data/lib/avo.rb +4 -0
  19. data/lib/avo/app/action.rb +8 -5
  20. data/lib/avo/app/app.rb +35 -28
  21. data/lib/avo/app/fields/belongs_to.rb +2 -2
  22. data/lib/avo/app/fields/code_field.rb +2 -0
  23. data/lib/avo/app/fields/country_field.rb +1 -1
  24. data/lib/avo/app/fields/field.rb +3 -1
  25. data/lib/avo/app/fields/field_extensions/visible_in_different_views.rb +4 -0
  26. data/lib/avo/app/fields/has_and_belongs_to_many.rb +1 -0
  27. data/lib/avo/app/fields/has_many.rb +1 -0
  28. data/lib/avo/app/fields/has_one.rb +2 -2
  29. data/lib/avo/app/fields/id_field.rb +4 -4
  30. data/lib/avo/app/fields/markdown_field.rb +27 -0
  31. data/lib/avo/app/fields/password_field.rb +3 -1
  32. data/lib/avo/app/fields/select_field.rb +1 -1
  33. data/lib/avo/app/licensing/community_license.rb +4 -0
  34. data/lib/avo/app/licensing/hq.rb +86 -0
  35. data/lib/avo/app/licensing/license.rb +48 -0
  36. data/lib/avo/app/licensing/license_manager.rb +25 -0
  37. data/lib/avo/app/licensing/null_license.rb +12 -0
  38. data/lib/avo/app/licensing/pro_license.rb +9 -0
  39. data/lib/avo/app/resource.rb +58 -20
  40. data/lib/avo/app/services/authorization_service.rb +40 -0
  41. data/lib/avo/configuration.rb +28 -2
  42. data/lib/avo/engine.rb +7 -7
  43. data/lib/avo/version.rb +1 -1
  44. data/lib/generators/avo/install_generator.rb +2 -1
  45. data/lib/generators/avo/templates/{initializer.rb → initializer/avo.rb} +2 -0
  46. data/lib/generators/avo/templates/locales/avo.en.yml +60 -0
  47. data/lib/generators/avo/templates/views/_scripts.html.erb +0 -0
  48. data/public/avo-packs/css/application-d405b262.css +3 -0
  49. data/public/avo-packs/css/application-d405b262.css.br +0 -0
  50. data/public/avo-packs/css/application-d405b262.css.gz +0 -0
  51. data/public/avo-packs/js/application-d7382d9da26e7470d7b2.js +3 -0
  52. data/public/avo-packs/js/{application-9a0dde96ad9918852965.js.LICENSE.txt → application-d7382d9da26e7470d7b2.js.LICENSE.txt} +0 -0
  53. data/public/avo-packs/js/application-d7382d9da26e7470d7b2.js.br +0 -0
  54. data/public/avo-packs/js/application-d7382d9da26e7470d7b2.js.gz +0 -0
  55. data/public/avo-packs/js/application-d7382d9da26e7470d7b2.js.map +1 -0
  56. data/public/avo-packs/js/application-d7382d9da26e7470d7b2.js.map.br +0 -0
  57. data/public/avo-packs/js/application-d7382d9da26e7470d7b2.js.map.gz +0 -0
  58. data/public/avo-packs/manifest.json +13 -6
  59. data/public/avo-packs/manifest.json.br +0 -0
  60. data/public/avo-packs/manifest.json.gz +0 -0
  61. data/public/avo-packs/media/font/fontello-068ca2b3.ttf +0 -0
  62. data/public/avo-packs/media/font/fontello-068ca2b3.ttf.br +0 -0
  63. data/public/avo-packs/media/font/fontello-068ca2b3.ttf.gz +0 -0
  64. data/public/avo-packs/media/font/fontello-8d4a4e6f.woff2 +0 -0
  65. data/public/avo-packs/media/font/fontello-9354499c.svg +72 -0
  66. data/public/avo-packs/media/font/fontello-9354499c.svg.br +0 -0
  67. data/public/avo-packs/media/font/fontello-9354499c.svg.gz +0 -0
  68. data/public/avo-packs/media/font/fontello-a782baa8.woff +0 -0
  69. data/public/avo-packs/media/font/fontello-e73a0647.eot +0 -0
  70. data/public/avo-packs/media/font/fontello-e73a0647.eot.br +0 -0
  71. data/public/avo-packs/media/font/fontello-e73a0647.eot.gz +0 -0
  72. data/public/avo-packs/media/svgs/arrow-circle-right-1ad1e15ec9a7aa54b67d126566a5aa2d.svg +1 -0
  73. data/public/avo-packs/media/svgs/arrow-circle-right-1ad1e15ec9a7aa54b67d126566a5aa2d.svg.br +0 -0
  74. data/public/avo-packs/media/svgs/arrow-circle-right-1ad1e15ec9a7aa54b67d126566a5aa2d.svg.gz +0 -0
  75. data/public/avo-packs/media/svgs/exclamation-8d1c0baa390a8df9bb52176011eb5892.svg +1 -0
  76. data/public/avo-packs/media/svgs/exclamation-8d1c0baa390a8df9bb52176011eb5892.svg.br +0 -0
  77. data/public/avo-packs/media/svgs/exclamation-8d1c0baa390a8df9bb52176011eb5892.svg.gz +0 -0
  78. metadata +88 -14
  79. data/public/avo-packs/css/application-5dc4dd78.css +0 -3
  80. data/public/avo-packs/css/application-5dc4dd78.css.br +0 -0
  81. data/public/avo-packs/css/application-5dc4dd78.css.gz +0 -0
  82. data/public/avo-packs/js/application-9a0dde96ad9918852965.js +0 -3
  83. data/public/avo-packs/js/application-9a0dde96ad9918852965.js.br +0 -0
  84. data/public/avo-packs/js/application-9a0dde96ad9918852965.js.gz +0 -0
  85. data/public/avo-packs/js/application-9a0dde96ad9918852965.js.map +0 -1
  86. data/public/avo-packs/js/application-9a0dde96ad9918852965.js.map.br +0 -0
  87. 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: f67836725edad209d1bae9be005a76e1e18ae3beba350d001c40e8ef036e1c11
4
- data.tar.gz: 8d529d3be11e43640ce68f25c1c4aaf1ffafd364eb33048c5911448f2f605f23
3
+ metadata.gz: 2d0554e2368fa7c0ec7518e5a7d8ae6ae4493261b137cfee5679bfabc8b375e2
4
+ data.tar.gz: 941940db42f14d0f095c78f41bb2a035869750b2446824ec446fc7e20fe90d1a
5
5
  SHA512:
6
- metadata.gz: bff44868735e4ff165a223d85c51ee947a274a0354c51c0de2fb42eeb520581bd3b421046c0782c0dba4871ed17436ad681382e0f210071c40e50e4f600d07c8
7
- data.tar.gz: 13eb639a2e7f92edacea34e4ccf52e7f8e177769ce6bb78083c448070c070ed2084c58897267920deed5e290558086c8c7690337a4ef89ed6cd4d9e981b42691
6
+ metadata.gz: 82c91e9d2ee921eaa5b29f06be220411eb094a3182cd0df56dd5896f15e9c4818b9a86f0363b9d8f0a024d7ad1c3bc8cdc8c44058c7d3145d231c0bb24ae15e9
7
+ data.tar.gz: 4e9f9a8fc861453488fdcc588618319d04e2078b0480b096a4c808bf9b1cb4100d3f07057fc9eafee6aef23bdfab20f07e14853e8ecd457a291d05bcb7274989
data/Gemfile CHANGED
@@ -23,54 +23,51 @@ gem 'inline_svg'
23
23
  gem 'countries'
24
24
 
25
25
  # Authorization
26
- gem "pundit"
27
-
28
- # These are the dummy app's dependencies
29
- group :development, :test do
30
- # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
31
- gem 'rails', '~> 6.0.2', '>= 6.0.2.2'
32
- # Use postgresql as the database for Active Record
33
- gem 'pg', '>= 0.18', '< 2.0'
34
- # Use Puma as the app server
35
- gem 'puma', '~> 4.3.5'
36
- # Use SCSS for stylesheets
37
- gem 'sass-rails', '>= 6'
38
- # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
39
- # gem 'turbolinks', '~> 5'
40
- # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
41
- gem 'jbuilder', '~> 2.7'
42
- # Use Redis adapter to run Action Cable in production
43
- # gem 'redis', '~> 4.0'
44
- # Use Active Model has_secure_password
45
- # gem 'bcrypt', '~> 3.1.7'
46
-
47
- # Use Active Storage variant
48
- # gem 'image_processing', '~> 1.2'
49
-
50
- # Reduces boot times through caching; required in config/boot.rb
51
- gem 'bootsnap', '>= 1.4.2', require: false
52
- # Call 'byebug' anywhere in the code to stop execution and get a debugger console
53
- gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
54
- gem 'dotenv-rails'
55
- # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
56
- gem 'web-console', '>= 3.3.0'
57
- gem 'listen', '>= 3.0.5', '< 3.2'
58
- # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
59
- gem 'spring'
60
- gem 'spring-watcher-listen', '~> 2.0.0'
61
-
62
- gem 'factory_bot_rails'
63
- gem 'faker'
64
-
65
- # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
66
- gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
67
-
68
- gem 'devise'
69
- gem 'database_cleaner'
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'
@@ -1,10 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (0.2.4)
4
+ avo (0.4.2)
5
5
  countries
6
+ httparty
7
+ i18n-js
6
8
  inline_svg
7
9
  kaminari
10
+ pundit
8
11
  rails (>= 6.0)
9
12
  webpacker
10
13
  zeitwerk
@@ -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,10 +1,11 @@
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
  ![](https://avohq.io/img/logo-full-stroke-tiny-2x.png)
6
7
 
7
- Configuration-based, no-maintenance, extendable Ruby on Rails admin
8
+ **Configuration-based, no-maintenance, extendable Ruby on Rails admin**
8
9
 
9
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.
10
11
 
@@ -13,7 +14,8 @@ Avo is a beautiful next-generation framework that empowers you, the developer, t
13
14
  **Website**: [avohq.io](https://avohq.io)\
14
15
  **Documentation**: [docs.avohq.io](https://docs.avohq.io)\
15
16
  **Twitter**: [avo_hq](https://twitter.com/avo_hq)\
16
- **Community**: [discord](https://discord.gg/pkTF6y8)
17
+ **Community chat**: [discord](https://discord.gg/pkTF6y8)\
18
+ **Issue tracker**: [GitHub issues](http://github.com/avo-hq/avo/issues)
17
19
 
18
20
  ## Features
19
21
 
@@ -27,7 +29,7 @@ Avo is a beautiful next-generation framework that empowers you, the developer, t
27
29
  - **Custom fields***- No worries if we missed a field you need. Generate a custom field in a jiffy.
28
30
  - **Dashboard widgets and metrics*** - Customize your dashboard with the tools and analytics you need.
29
31
  - **Custom tools*** - You need to add a page with something completely new, you've got it!
30
- - **Authorization*** - Leverage Pundit policies to build a robust and scalable authorization system.
32
+ - **Authorization** - Leverage Pundit policies to build a robust and scalable authorization system.
31
33
  - **Themable*** - Dress it up into your own colors.
32
34
  - **Localization*** - Have it available in any language you need.
33
35
 
@@ -5,7 +5,10 @@ module Avo
5
5
  before_action :init_app
6
6
 
7
7
  def init_app
8
- Avo::App.init
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.map do |resource|
7
- {
8
- name: resource.name,
9
- url: resource.url,
10
- count: resource.model.count,
11
- }
12
- end
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
- filters = get_filters
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 reated resource (via_resource)
14
- related_resource = App.get_resource_by_name(params[:via_resource_name])
15
- related_model = related_resource.model
16
- # fetch the entries
17
- query = related_model.find(params[:via_resource_id]).public_send(params[:via_relationship])
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
- if filters.present?
37
- filters.each do |filter_class, filter_value|
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 lood the relations
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: 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: 'Resource updated',
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: 'Resource created',
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 fields
152
- resource = resource_model.new
153
-
125
+ def new
154
126
  render json: {
155
- resource: Avo::Resources::Resource.hydrate_resource(resource, avo_resource, :create),
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: 'Resource destroyed',
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 get_filters
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