ab_admin 0.9.0 → 0.10.0
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/app/assets/javascripts/ab_admin/components/in_place_edit.js.coffee +28 -24
- data/app/assets/javascripts/ab_admin/core/batch_actions.js.coffee +1 -1
- data/app/assets/javascripts/ab_admin/core/init.js.coffee +1 -0
- data/app/assets/javascripts/ab_admin/core/ui_utils.js.coffee +21 -1
- data/app/assets/javascripts/ab_admin/core/utils.js.coffee +8 -0
- data/app/assets/javascripts/ab_admin/inputs/datetime_input.js.coffee +1 -0
- data/app/assets/javascripts/ab_admin/main.js +1 -2
- data/app/assets/stylesheets/ab_admin/bootstrap_and_overrides.scss +44 -23
- data/app/assets/stylesheets/ab_admin/components/_colored_tabs.scss +1 -1
- data/app/assets/stylesheets/ab_admin/components/_form.scss +3 -1
- data/app/assets/stylesheets/ab_admin/components/_navigation.scss +7 -2
- data/app/assets/stylesheets/ab_admin/components/_table_view.scss +75 -9
- data/app/assets/stylesheets/ab_admin/components/_tooltip.scss +1 -0
- data/app/assets/stylesheets/ab_admin/main.scss +1 -1
- data/app/controllers/admin/assets_controller.rb +1 -1
- data/app/controllers/admin/base_controller.rb +87 -107
- data/app/controllers/admin/manager_controller.rb +17 -47
- data/app/views/ab_admin/devise/sessions/new.html.slim +2 -0
- data/app/views/admin/assets/batch_edit.html.slim +2 -1
- data/app/views/admin/base/_search_layout.html.slim +1 -1
- data/app/views/admin/base/create.js.erb +1 -1
- data/app/views/admin/base/edit.js.erb +1 -1
- data/app/views/admin/base/new.js.erb +1 -1
- data/app/views/admin/base/update.js.erb +3 -3
- data/app/views/admin/manager/_show_table.html.slim +1 -1
- data/app/views/admin/manager/_stats.html.slim +4 -0
- data/app/views/admin/manager/_table.html.slim +6 -3
- data/app/views/admin/shared/_content_actions.html.slim +22 -15
- data/app/views/admin/shared/_save_buttons.html.slim +10 -1
- data/app/views/admin/users/_form.html.slim +2 -2
- data/config/locales/en.yml +8 -13
- data/config/locales/it.yml +1 -0
- data/db/migrate/20130101000001_create_users.rb +1 -4
- data/db/migrate/20130101000003_create_assets.rb +1 -1
- data/db/migrate/20130101000004_create_headers.rb +5 -5
- data/db/migrate/20130101000005_create_static_pages.rb +2 -5
- data/db/migrate/20130101000006_create_structures.rb +1 -1
- data/db/migrate/20130101000007_base_translations.rb +43 -12
- data/db/migrate/20130101000008_create_admin_comments.rb +2 -7
- data/db/migrate/20130101000009_create_tracks.rb +4 -8
- data/lib/ab_admin/abstract_resource.rb +6 -5
- data/lib/ab_admin/carrierwave/base_uploader.rb +87 -74
- data/lib/ab_admin/carrierwave/glue.rb +0 -5
- data/lib/ab_admin/concerns/admin_addition.rb +19 -1
- data/lib/ab_admin/concerns/utilities.rb +1 -1
- data/lib/ab_admin/config/base.rb +20 -4
- data/lib/ab_admin/core_ext/array.rb +0 -5
- data/lib/ab_admin/core_ext/string.rb +1 -6
- data/lib/ab_admin/devise.rb +7 -0
- data/lib/ab_admin/engine.rb +1 -1
- data/lib/ab_admin/hooks/ckeditor_lazy.rb +13 -0
- data/lib/ab_admin/menu/base_group.rb +0 -1
- data/lib/ab_admin/menu/group.rb +2 -4
- data/lib/ab_admin/menu/item.rb +4 -8
- data/lib/ab_admin/models/asset.rb +7 -10
- data/lib/ab_admin/models/locator.rb +1 -1
- data/lib/ab_admin/models/settings.rb +2 -2
- data/lib/ab_admin/models/structure.rb +3 -3
- data/lib/ab_admin/models/track.rb +15 -3
- data/lib/ab_admin/utils/csv_document.rb +4 -4
- data/lib/ab_admin/utils/eval_helpers.rb +0 -16
- data/lib/ab_admin/utils/logger.rb +12 -2
- data/lib/ab_admin/utils/mysql.rb +2 -3
- data/lib/ab_admin/utils/xls_document.rb +1 -3
- data/lib/ab_admin/utils.rb +0 -5
- data/lib/ab_admin/version.rb +1 -1
- data/lib/ab_admin/views/admin_helpers.rb +33 -16
- data/lib/ab_admin/views/admin_navigation_helpers.rb +12 -9
- data/lib/ab_admin/views/inputs/ckeditor_input.rb +1 -5
- data/lib/ab_admin/views/manager_helpers.rb +9 -3
- data/lib/ab_admin/views/search_form_builder.rb +12 -12
- data/lib/ab_admin.rb +13 -2
- data/lib/generators/ab_admin/install/templates/models/user.rb +1 -2
- data/lib/generators/ab_admin/install/templates/uploaders/attachment_file_uploader.rb +1 -1
- data/lib/generators/ab_admin/install/templates/uploaders/avatar_uploader.rb +1 -1
- data/lib/generators/ab_admin/install/templates/uploaders/picture_uploader.rb +16 -3
- data/lib/generators/ab_admin/resource/resource_generator.rb +0 -4
- data/lib/generators/ab_admin/resource/templates/controller.erb +0 -7
- data/lib/tasks/assets.rake +5 -5
- metadata +28 -26
data/config/locales/en.yml
CHANGED
|
@@ -18,22 +18,13 @@ en:
|
|
|
18
18
|
actions:
|
|
19
19
|
activate:
|
|
20
20
|
link: Activate
|
|
21
|
-
batch_destroy:
|
|
22
|
-
confirmation: Are you sure you want to delete the selected records?
|
|
23
|
-
link: Delete selected
|
|
24
|
-
title: Multi-remove
|
|
25
|
-
batch_publish:
|
|
26
|
-
link: Publish selected
|
|
27
|
-
title: Multi-publish
|
|
28
|
-
batch_un_publish:
|
|
29
|
-
link: Unpublish selected
|
|
30
|
-
title: Multi-hiding
|
|
31
21
|
create:
|
|
32
22
|
link: Create
|
|
33
23
|
title: Creation
|
|
34
24
|
destroy:
|
|
35
|
-
link:
|
|
36
|
-
title:
|
|
25
|
+
link: Destroy
|
|
26
|
+
title: Destroy
|
|
27
|
+
confirmation: Are you sure you want to delete the selected records?
|
|
37
28
|
edit:
|
|
38
29
|
link: Edit
|
|
39
30
|
title: Editing
|
|
@@ -94,7 +85,7 @@ en:
|
|
|
94
85
|
comments:
|
|
95
86
|
add: Comment
|
|
96
87
|
title_content: Comments (%{count})
|
|
97
|
-
delete:
|
|
88
|
+
delete: Destroy
|
|
98
89
|
delete_confirmation: Are you sure you want to delete this?
|
|
99
90
|
empty: Empty
|
|
100
91
|
exit: Output
|
|
@@ -109,6 +100,8 @@ en:
|
|
|
109
100
|
form:
|
|
110
101
|
cancel: Cancel
|
|
111
102
|
save: Save
|
|
103
|
+
force_save: Force save
|
|
104
|
+
refresh: Refresh
|
|
112
105
|
save_and_add_another: Save and add new
|
|
113
106
|
save_and_edit: Save and continue editing
|
|
114
107
|
save_and_edit_next: Save and next.
|
|
@@ -245,6 +238,7 @@ en:
|
|
|
245
238
|
updater_id: 'Updater'
|
|
246
239
|
remember_me: Remember
|
|
247
240
|
password: Password
|
|
241
|
+
otp_attempt: OTP
|
|
248
242
|
flash:
|
|
249
243
|
admin:
|
|
250
244
|
actions:
|
|
@@ -290,5 +284,6 @@ en:
|
|
|
290
284
|
size_too_big: is too big (should be at most %{file_size})
|
|
291
285
|
carrierwave_processing_error: Cannot resize image.
|
|
292
286
|
carrierwave_integrity_error: Not an image.
|
|
287
|
+
changed: 'Record was changed by someone else, "Refresh" to get the latest version and repeat changes or "Force save" to overwrite'
|
|
293
288
|
unauthorized:
|
|
294
289
|
default: You are not authorized to access this page.
|
data/config/locales/it.yml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class CreateUsers < ActiveRecord::Migration
|
|
1
|
+
class CreateUsers < ActiveRecord::Migration[5.2]
|
|
2
2
|
def change
|
|
3
3
|
create_table(:users) do |t|
|
|
4
4
|
t.string :login
|
|
@@ -35,9 +35,6 @@ class CreateUsers < ActiveRecord::Migration
|
|
|
35
35
|
t.string :current_sign_in_ip
|
|
36
36
|
t.string :last_sign_in_ip
|
|
37
37
|
|
|
38
|
-
## Encryptable
|
|
39
|
-
t.string :password_salt
|
|
40
|
-
|
|
41
38
|
## Confirmable
|
|
42
39
|
t.string :confirmation_token
|
|
43
40
|
t.datetime :confirmed_at
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
class CreateHeaders < ActiveRecord::Migration
|
|
1
|
+
class CreateHeaders < ActiveRecord::Migration[5.2]
|
|
2
2
|
def change
|
|
3
3
|
create_table :headers do |t|
|
|
4
|
-
t.string
|
|
5
|
-
t.integer
|
|
6
|
-
|
|
4
|
+
t.string :headerable_type, limit: 50, null: false
|
|
5
|
+
t.integer :headerable_id, null: false
|
|
6
|
+
|
|
7
7
|
t.timestamps
|
|
8
8
|
end
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
add_index :headers, [:headerable_type, :headerable_id], unique: true
|
|
11
11
|
end
|
|
12
12
|
end
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
class CreateStaticPages < ActiveRecord::Migration
|
|
1
|
+
class CreateStaticPages < ActiveRecord::Migration[5.2]
|
|
2
2
|
def change
|
|
3
3
|
create_table :static_pages do |t|
|
|
4
|
-
t.
|
|
4
|
+
t.references :structure, null: false
|
|
5
5
|
t.references :user
|
|
6
6
|
t.boolean :is_visible, default: true, null: false
|
|
7
7
|
|
|
8
8
|
t.timestamps
|
|
9
9
|
end
|
|
10
|
-
|
|
11
|
-
add_index :static_pages, :user_id
|
|
12
|
-
add_index :static_pages, :structure_id
|
|
13
10
|
end
|
|
14
11
|
end
|
|
@@ -1,15 +1,46 @@
|
|
|
1
|
-
class BaseTranslations < ActiveRecord::Migration
|
|
2
|
-
def
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
class BaseTranslations < ActiveRecord::Migration[5.2]
|
|
2
|
+
def change
|
|
3
|
+
create_table :static_page_translations do |t|
|
|
4
|
+
t.references :static_page, null: false
|
|
5
|
+
t.string :locale, limit: 5, null: false
|
|
6
|
+
t.string :title
|
|
7
|
+
t.text :content
|
|
8
|
+
|
|
9
|
+
t.timestamps
|
|
10
|
+
end
|
|
11
|
+
add_index :static_page_translations, [:static_page_id, :locale], unique: true, name: 'static_pages_ts_static_page_id_locale'
|
|
12
|
+
|
|
13
|
+
create_table :header_translations do |t|
|
|
14
|
+
t.references :header, null: false
|
|
15
|
+
t.string :locale, limit: 5, null: false
|
|
16
|
+
t.string :title
|
|
17
|
+
t.string :h1
|
|
18
|
+
t.string :keywords
|
|
19
|
+
t.text :description
|
|
20
|
+
t.text :seo_block
|
|
21
|
+
|
|
22
|
+
t.timestamps
|
|
23
|
+
end
|
|
24
|
+
add_index :header_translations, [:header_id, :locale], unique: true, name: 'headers_ts_header_id_locale'
|
|
25
|
+
|
|
26
|
+
create_table :structure_translations do |t|
|
|
27
|
+
t.references :structure, null: false
|
|
28
|
+
t.string :locale, limit: 5, null: false
|
|
29
|
+
t.string :title
|
|
30
|
+
t.string :redirect_url
|
|
31
|
+
|
|
32
|
+
t.timestamps
|
|
33
|
+
end
|
|
34
|
+
add_index :structure_translations, [:structure_id, :locale], unique: true, name: 'structures_ts_structure_id_locale'
|
|
35
|
+
|
|
36
|
+
create_table :asset_translations do |t|
|
|
37
|
+
t.references :asset, null: false
|
|
38
|
+
t.string :locale, limit: 5, null: false
|
|
39
|
+
t.string :name
|
|
40
|
+
t.string :alt
|
|
8
41
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
Structure.drop_translation_table!
|
|
13
|
-
Asset.drop_translation_table!
|
|
42
|
+
t.timestamps
|
|
43
|
+
end
|
|
44
|
+
add_index :asset_translations, [:asset_id, :locale], unique: true, name: 'assets_ts_asset_id_locale'
|
|
14
45
|
end
|
|
15
46
|
end
|
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
class CreateAdminComments < ActiveRecord::Migration
|
|
1
|
+
class CreateAdminComments < ActiveRecord::Migration[5.2]
|
|
2
2
|
def change
|
|
3
3
|
create_table :admin_comments do |t|
|
|
4
4
|
t.references :user
|
|
5
5
|
t.string :user_name
|
|
6
|
-
t.
|
|
7
|
-
t.string :resource_type, limit: 50, null: false
|
|
6
|
+
t.references :resource, polymorphic: true
|
|
8
7
|
t.references :resource_user
|
|
9
8
|
t.text :body
|
|
10
9
|
|
|
11
10
|
t.timestamps
|
|
12
11
|
end
|
|
13
|
-
|
|
14
|
-
add_index :admin_comments, :user_id
|
|
15
|
-
add_index :admin_comments, :resource_user_id
|
|
16
|
-
add_index :admin_comments, [:resource_type, :resource_id]
|
|
17
12
|
end
|
|
18
13
|
end
|
|
@@ -1,20 +1,16 @@
|
|
|
1
|
-
class CreateTracks < ActiveRecord::Migration
|
|
1
|
+
class CreateTracks < ActiveRecord::Migration[5.2]
|
|
2
2
|
def change
|
|
3
3
|
create_table :tracks do |t|
|
|
4
4
|
t.string :name
|
|
5
5
|
t.string :key
|
|
6
|
-
t.
|
|
7
|
-
t.
|
|
8
|
-
t.
|
|
6
|
+
t.references :trackable, polymorphic: true
|
|
7
|
+
t.references :user
|
|
8
|
+
t.references :owner
|
|
9
9
|
t.column :trackable_changes, :mediumtext
|
|
10
10
|
t.text :parameters
|
|
11
11
|
|
|
12
12
|
t.timestamps
|
|
13
13
|
end
|
|
14
|
-
|
|
15
|
-
add_index :tracks, [:trackable_type, :trackable_id]
|
|
16
|
-
add_index :tracks, :owner_id
|
|
17
|
-
add_index :tracks, :user_id
|
|
18
14
|
add_index :tracks, :key
|
|
19
15
|
end
|
|
20
16
|
end
|
|
@@ -6,14 +6,15 @@ module AbAdmin
|
|
|
6
6
|
ACTIONS = [:index, :show, :new, :edit, :create, :update, :destroy, :preview, :batch, :rebuild, :custom_action, :history]
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
attr_accessor :model, :table, :search, :export, :form, :chart, :map, :modal_form, :show,
|
|
10
|
-
:
|
|
9
|
+
attr_accessor :model, :table, :search, :export, :form, :chart, :stats, :map, :modal_form, :show,
|
|
10
|
+
:preview_path, :actions, :custom_settings,
|
|
11
|
+
:batch_actions, :action_items, :disabled_action_items, :resource_action_items, :tree_node_renderer,
|
|
11
12
|
:parent_resources, :custom_actions, :permitted_params, :scopes
|
|
12
13
|
|
|
13
14
|
def initialize
|
|
14
15
|
@actions = ACTIONS
|
|
15
16
|
@custom_settings = {}
|
|
16
|
-
@
|
|
17
|
+
@batch_actions= [AbAdmin::Config::BatchAction.new(:destroy, confirm: I18n.t('admin.delete_confirmation'))]
|
|
17
18
|
@action_items = []
|
|
18
19
|
@disabled_action_items = []
|
|
19
20
|
@default_action_items_for = {}
|
|
@@ -87,9 +88,9 @@ module AbAdmin
|
|
|
87
88
|
|
|
88
89
|
def batch_action(name, options={}, &block)
|
|
89
90
|
if options
|
|
90
|
-
instance.
|
|
91
|
+
instance.batch_actions << AbAdmin::Config::BatchAction.new(name.to_sym, options, &block)
|
|
91
92
|
else
|
|
92
|
-
instance.
|
|
93
|
+
instance.batch_actions.reject!{|a| a.name == name.to_sym }
|
|
93
94
|
end
|
|
94
95
|
end
|
|
95
96
|
|
|
@@ -7,8 +7,7 @@ module AbAdmin
|
|
|
7
7
|
include ::CarrierWave::MiniMagick
|
|
8
8
|
include AbAdmin::Utils::EvalHelpers
|
|
9
9
|
|
|
10
|
-
class_attribute :
|
|
11
|
-
self.transliterate = true
|
|
10
|
+
class_attribute :human_filenames
|
|
12
11
|
self.human_filenames = true
|
|
13
12
|
|
|
14
13
|
attr_accessor :internal_identifier
|
|
@@ -25,41 +24,48 @@ module AbAdmin
|
|
|
25
24
|
|
|
26
25
|
process :set_model_info
|
|
27
26
|
|
|
28
|
-
def
|
|
29
|
-
"#{
|
|
27
|
+
def filename
|
|
28
|
+
"#{[human_part, secure_token].compact.join('_')}#{extension}"
|
|
30
29
|
end
|
|
31
30
|
|
|
32
|
-
def
|
|
33
|
-
|
|
31
|
+
def full_filename(*)
|
|
32
|
+
return filename unless version_name
|
|
33
|
+
base = "#{version_filename_part}#{version_extension}"
|
|
34
|
+
return base unless human_filenames
|
|
35
|
+
[human_part, base].compact.join('_')
|
|
34
36
|
end
|
|
35
37
|
|
|
36
|
-
def
|
|
37
|
-
|
|
38
|
-
return secure_token unless version_name
|
|
39
|
-
version_name.to_s.start_with?('retina_') ? "#{version_name.to_s.sub(/^retina_/, '')}@2x" : version_name.to_s
|
|
38
|
+
def human_part
|
|
39
|
+
normalize_filename(model.send("#{mounted_as}_file_name").to_s.strip.remove(/\.\w+$/)).remove(secure_token).chomp('_').presence
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
def
|
|
43
|
-
|
|
42
|
+
def extension
|
|
43
|
+
File.extname(model.original_name).downcase
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
def
|
|
47
|
-
|
|
48
|
-
system_part = base_filename_part
|
|
49
|
-
human_filename_part = for_file.chomp(ext)
|
|
50
|
-
return "#{system_part || version_name}#{ext}" if human_filename_part == secure_token
|
|
51
|
-
system_part ? "#{human_filename_part}_#{system_part}#{ext}" : "#{human_filename_part}#{ext}"
|
|
46
|
+
def version_extension
|
|
47
|
+
webp? ? '.webp' : extension
|
|
52
48
|
end
|
|
53
49
|
|
|
54
|
-
def
|
|
55
|
-
|
|
50
|
+
def version_filename_part
|
|
51
|
+
return secure_token unless version_name
|
|
52
|
+
strict_version_name = version_name.to_s.remove('retina_').remove('_webp')
|
|
53
|
+
strict_version_name = nil if strict_version_name.to_sym == :default
|
|
54
|
+
"#{strict_version_name}#{'@2x' if retina?}"
|
|
56
55
|
end
|
|
57
56
|
|
|
58
|
-
# use secure token in the filename for non processed image
|
|
59
57
|
def secure_token
|
|
60
58
|
model.data_secure_token ||= AbAdmin.friendly_token(20).downcase
|
|
61
59
|
end
|
|
62
60
|
|
|
61
|
+
def retina?
|
|
62
|
+
version_name.to_s.start_with?('retina_')
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def webp?
|
|
66
|
+
version_name.to_s.end_with?('_webp')
|
|
67
|
+
end
|
|
68
|
+
|
|
63
69
|
def store_model_filename(record)
|
|
64
70
|
old_file_name = filename
|
|
65
71
|
new_file_name = model_filename(old_file_name, record)
|
|
@@ -67,69 +73,81 @@ module AbAdmin
|
|
|
67
73
|
rename_via_move(new_file_name)
|
|
68
74
|
end
|
|
69
75
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def filename
|
|
73
|
-
internal_identifier || model.send("#{mounted_as}_file_name") || (store_filename && "#{secure_token}#{File.extname(store_filename).downcase}")
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def write_internal_identifier(internal_identifier)
|
|
77
|
-
self.internal_identifier = internal_identifier
|
|
78
|
-
versions.values.each{|v| v.internal_identifier = internal_identifier }
|
|
76
|
+
def save_original_name(file)
|
|
77
|
+
model.original_name ||= file.original_filename if file.respond_to?(:original_filename)
|
|
79
78
|
end
|
|
80
79
|
|
|
81
|
-
# transliterate original filename
|
|
82
|
-
# allow to build custom filename
|
|
83
80
|
def model_filename(base_filename, record)
|
|
84
81
|
custom_file_name = model.build_filename(base_filename, record)
|
|
85
82
|
return unless custom_file_name
|
|
86
|
-
normalize_filename(custom_file_name)
|
|
83
|
+
normalize_filename(custom_file_name)
|
|
87
84
|
end
|
|
85
|
+
private :model_filename
|
|
88
86
|
|
|
89
87
|
def normalize_filename(raw_filename)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
to_path = File.join(dir, v.full_filename(new_file_name))
|
|
103
|
-
next if from_path == to_path || !File.exists?(from_path)
|
|
104
|
-
moves << [from_path, to_path]
|
|
105
|
-
end
|
|
106
|
-
moves.each { |move| FileUtils.mv(*move) }
|
|
88
|
+
I18n.transliterate(raw_filename.unicode_normalize).parameterize(separator: '_').gsub(/[\-_]+/, '_').downcase
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def rename_via_move(new_filename)
|
|
92
|
+
dir = File.dirname(path)
|
|
93
|
+
old_names = versions.values.unshift(self).map(&:full_filename)
|
|
94
|
+
model.send("#{mounted_as}_file_name=", "#{[new_filename.presence, secure_token].compact.join('_')}#{extension}")
|
|
95
|
+
new_names = versions.values.unshift(self).map(&:full_filename)
|
|
96
|
+
old_names.zip(new_names).each do |old_name, new_name|
|
|
97
|
+
old_path, new_path = File.join(dir, old_name), File.join(dir, new_name)
|
|
98
|
+
next if old_path == new_path || !File.exist?(old_path)
|
|
99
|
+
FileUtils.mv(old_path, new_path)
|
|
107
100
|
end
|
|
108
|
-
|
|
109
|
-
write_internal_identifier new_file_name
|
|
110
|
-
model.send("write_#{mounted_as}_identifier")
|
|
111
|
-
retrieve_from_store!(new_file_name) if human_filenames
|
|
112
|
-
|
|
113
|
-
new_file_name
|
|
101
|
+
retrieve_from_store!(model.send("#{mounted_as}_file_name"))
|
|
114
102
|
end
|
|
115
103
|
|
|
116
|
-
private :write_internal_identifier, :store_filename, :model_filename
|
|
117
|
-
|
|
118
|
-
def rmagick_included?
|
|
119
|
-
self.class.included_modules.map(&:to_s).include?('CarrierWave::RMagick')
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
# prevent large number of subdirectories
|
|
123
104
|
def store_dir
|
|
124
105
|
str_id = model.id.to_s.rjust(4, '0')
|
|
125
106
|
[AbAdmin.uploads_dir, model.class.to_s.underscore, str_id[0..2], str_id[3..-1]].join('/')
|
|
126
107
|
end
|
|
127
108
|
|
|
109
|
+
def convert_to_webp(options = {})
|
|
110
|
+
webp_path = "#{File.dirname(path)}/#{full_filename}"
|
|
111
|
+
WebP.encode(path, webp_path, options_for_webp(options))
|
|
112
|
+
@file = ::CarrierWave::SanitizedFile.new(tempfile: webp_path, filename: webp_path, content_type: 'image/webp')
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def options_for_webp(options)
|
|
116
|
+
w, h = width, height
|
|
117
|
+
options = options.dup
|
|
118
|
+
ratio = w.to_f / h
|
|
119
|
+
if options[:resize_to_fill]
|
|
120
|
+
res_w, res_h = options[:resize_to_fill]
|
|
121
|
+
res_ratio = res_w.to_f / res_h
|
|
122
|
+
options.update(resize_w: res_w, resize_h: res_h) unless w == res_w && h == res_h
|
|
123
|
+
if ratio > res_ratio
|
|
124
|
+
crop_res_w = h * res_ratio
|
|
125
|
+
crop_res_h = h
|
|
126
|
+
options.update(crop_x: ((w - crop_res_w) / 2).to_i, crop_y: 0, crop_w: crop_res_w.to_i, crop_h: crop_res_h.to_i)
|
|
127
|
+
elsif ratio < res_ratio
|
|
128
|
+
crop_res_w = w
|
|
129
|
+
crop_res_h = w / res_ratio
|
|
130
|
+
options.update(crop_x: 0, crop_y: ((h - crop_res_h) / 2).to_i, crop_w: crop_res_w.to_i, crop_h: crop_res_h.to_i)
|
|
131
|
+
end
|
|
132
|
+
elsif options[:resize_to_fit]
|
|
133
|
+
res_w, res_h = options[:resize_to_fit]
|
|
134
|
+
res_ratio = res_w.to_f / res_h
|
|
135
|
+
if ratio == res_ratio
|
|
136
|
+
options.update(resize_w: res_w, resize_h: res_h) unless w == res_w && h == res_h
|
|
137
|
+
elsif ratio > res_ratio
|
|
138
|
+
options.update(resize_w: res_h)
|
|
139
|
+
elsif ratio < res_ratio
|
|
140
|
+
options.update(resize_h: res_w)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
options.except(:resize_to_fill, :resize_to_fit)
|
|
144
|
+
end
|
|
145
|
+
|
|
128
146
|
# Strips out all embedded information from the image
|
|
129
147
|
# process :strip
|
|
130
148
|
#
|
|
131
149
|
def strip
|
|
132
|
-
|
|
150
|
+
minimagick! do |img|
|
|
133
151
|
img.strip
|
|
134
152
|
img = yield(img) if block_given?
|
|
135
153
|
img
|
|
@@ -143,7 +161,7 @@ module AbAdmin
|
|
|
143
161
|
percentage = normalize_param(percentage)
|
|
144
162
|
|
|
145
163
|
unless percentage.blank?
|
|
146
|
-
|
|
164
|
+
minimagick! do |img|
|
|
147
165
|
img.quality percentage.to_s
|
|
148
166
|
img = yield(img) if block_given?
|
|
149
167
|
img
|
|
@@ -159,7 +177,7 @@ module AbAdmin
|
|
|
159
177
|
|
|
160
178
|
unless degrees.blank?
|
|
161
179
|
manipulate! do |img|
|
|
162
|
-
|
|
180
|
+
self.class.included_modules.map(&:to_s).include?('CarrierWave::RMagick') ? img.rotate!(degrees.to_i) : img.rotate(degrees.to_s)
|
|
163
181
|
img = yield(img) if block_given?
|
|
164
182
|
img
|
|
165
183
|
end
|
|
@@ -175,7 +193,7 @@ module AbAdmin
|
|
|
175
193
|
geometry = normalize_param(geometry[0]) if geometry.size == 1
|
|
176
194
|
|
|
177
195
|
if geometry && geometry.size == 4
|
|
178
|
-
|
|
196
|
+
minimagick! do |img|
|
|
179
197
|
img.crop '%ix%i+%i+%i' % geometry
|
|
180
198
|
img = yield(img) if block_given?
|
|
181
199
|
img
|
|
@@ -184,7 +202,7 @@ module AbAdmin
|
|
|
184
202
|
end
|
|
185
203
|
|
|
186
204
|
def watermark(watermark_path, gravity='SouthEast')
|
|
187
|
-
|
|
205
|
+
minimagick! do |img|
|
|
188
206
|
resolved_path = watermark_path.is_a?(Symbol) ? send(watermark_path) : watermark_path
|
|
189
207
|
watermark_image = ::MiniMagick::Image.open(resolved_path)
|
|
190
208
|
img.composite(watermark_image) { |c| c.gravity gravity }
|
|
@@ -201,12 +219,7 @@ module AbAdmin
|
|
|
201
219
|
end
|
|
202
220
|
|
|
203
221
|
def dimensions
|
|
204
|
-
[
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
def magick
|
|
208
|
-
#@magick ||= ::MiniMagick::Image.new(current_path)
|
|
209
|
-
::MiniMagick::Image.new(current_path)
|
|
222
|
+
[width, height]
|
|
210
223
|
end
|
|
211
224
|
|
|
212
225
|
protected
|
|
@@ -11,11 +11,6 @@ module AbAdmin
|
|
|
11
11
|
mount_uploader(:data, uploader, options, &block)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def sunrise_uploader(*args)
|
|
15
|
-
ActiveSupport::Deprecation.warn('`sunrise_uploader` is deprecated, use `ab_admin_uploader` instead')
|
|
16
|
-
ab_admin_uploader(*args)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
14
|
def validates_filesize_of(*attr_names)
|
|
20
15
|
validates_with FileSizeValidator, _merge_attributes(attr_names)
|
|
21
16
|
end
|
|
@@ -4,14 +4,25 @@ module AbAdmin
|
|
|
4
4
|
extend ActiveSupport::Concern
|
|
5
5
|
|
|
6
6
|
included do
|
|
7
|
+
attr_accessor :last_updated_timestamp
|
|
8
|
+
validate :do_not_overwrite, if: :last_updated_timestamp
|
|
7
9
|
scope(:admin, proc { all }) unless respond_to?(:admin)
|
|
8
10
|
scope(:base, -> { all }) unless respond_to?(:base)
|
|
9
|
-
scope :by_ids, lambda { |ids| where("#{quoted_table_name}.id IN (?)", AbAdmin.val_to_array(ids).push(0)) } unless respond_to?(:by_ids)
|
|
10
11
|
|
|
11
12
|
class_attribute :batch_actions, instance_writer: false
|
|
12
13
|
self.batch_actions = [:destroy]
|
|
13
14
|
end
|
|
14
15
|
|
|
16
|
+
def updated_timestamp(associations: true)
|
|
17
|
+
res = [updated_at]
|
|
18
|
+
res += translations.map(&:updated_at) if self.class.translates?
|
|
19
|
+
if associations
|
|
20
|
+
associations = self.class.nested_attributes_options.keys unless associations.is_a?(Array)
|
|
21
|
+
res += associations.flat_map{|assoc| Array(send(assoc)).map(&:updated_timestamp) }
|
|
22
|
+
end
|
|
23
|
+
res.compact.max
|
|
24
|
+
end
|
|
25
|
+
|
|
15
26
|
def for_input_token
|
|
16
27
|
{id: id, text: AbAdmin.safe_display_name(self).to_s}
|
|
17
28
|
end
|
|
@@ -63,6 +74,13 @@ module AbAdmin
|
|
|
63
74
|
sql = "(#{quoted_order_col} #{predicate} :val OR (#{quoted_order_col} = :val AND #{self.class.quote_column('id')} #{id_predicate} #{id}))"
|
|
64
75
|
scope.where(sql, val: send(order_col)).ransack(query[:q]).result(distinct: true).first
|
|
65
76
|
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def do_not_overwrite
|
|
81
|
+
return if new_record? || last_updated_timestamp.blank?
|
|
82
|
+
errors.add(:base, :changed) if updated_timestamp.to_i > last_updated_timestamp.to_i
|
|
83
|
+
end
|
|
66
84
|
end
|
|
67
85
|
end
|
|
68
86
|
end
|
|
@@ -70,7 +70,7 @@ module AbAdmin
|
|
|
70
70
|
add_cond << assoc.klass.instance_exec(&assoc.scope).to_sql[/WHERE(.*?)(?:(?:ORDER|LIMIT).*)?$/, 1] if assoc.scope
|
|
71
71
|
if assoc.klass.default_scopes.present?
|
|
72
72
|
assoc.klass.default_scopes.each do |scope|
|
|
73
|
-
add_cond << scope.call.to_sql[/WHERE(.*?)(?:(?:ORDER|LIMIT).*)?$/, 1]
|
|
73
|
+
add_cond << scope.scope.call.to_sql[/WHERE(.*?)(?:(?:ORDER|LIMIT).*)?$/, 1]
|
|
74
74
|
end
|
|
75
75
|
end
|
|
76
76
|
count_klass = assoc_count.klass
|
data/lib/ab_admin/config/base.rb
CHANGED
|
@@ -32,6 +32,11 @@ module AbAdmin
|
|
|
32
32
|
|
|
33
33
|
class Table < BaseBuilder
|
|
34
34
|
self.partial_name = 'table'
|
|
35
|
+
|
|
36
|
+
def row_html_class
|
|
37
|
+
return :row_html_class if options[:row_html_class].is_a?(TrueClass)
|
|
38
|
+
options[:row_html_class]
|
|
39
|
+
end
|
|
35
40
|
end
|
|
36
41
|
|
|
37
42
|
class Search < BaseBuilder
|
|
@@ -42,6 +47,10 @@ module AbAdmin
|
|
|
42
47
|
self.partial_name = 'chart'
|
|
43
48
|
end
|
|
44
49
|
|
|
50
|
+
class Stats < BaseBuilder
|
|
51
|
+
self.partial_name = 'stats'
|
|
52
|
+
end
|
|
53
|
+
|
|
45
54
|
class Map < BaseBuilder
|
|
46
55
|
self.partial_name = 'map'
|
|
47
56
|
end
|
|
@@ -118,7 +127,7 @@ module AbAdmin
|
|
|
118
127
|
end
|
|
119
128
|
|
|
120
129
|
class BatchAction
|
|
121
|
-
attr_reader :name, :options, :data, :
|
|
130
|
+
attr_reader :name, :options, :data, :form
|
|
122
131
|
|
|
123
132
|
def initialize(name, options={}, &block)
|
|
124
133
|
@name = name
|
|
@@ -126,10 +135,13 @@ module AbAdmin
|
|
|
126
135
|
if options.has_key?(:form)
|
|
127
136
|
@form = options[:form].is_a?(String) ? options[:form] : "##{name}_batch_form"
|
|
128
137
|
end
|
|
129
|
-
@title = options[:title] || I18n.t("admin.actions.batch_#{name}.link", default: name.to_s.humanize)
|
|
130
138
|
@data = block_given? ? block : name.to_sym
|
|
131
139
|
end
|
|
132
140
|
|
|
141
|
+
def title
|
|
142
|
+
options[:title] || I18n.t("admin.actions.#{name}.title", default: name.to_s.humanize)
|
|
143
|
+
end
|
|
144
|
+
|
|
133
145
|
def confirm
|
|
134
146
|
options[:confirm]
|
|
135
147
|
end
|
|
@@ -176,8 +188,12 @@ module AbAdmin
|
|
|
176
188
|
@data = block
|
|
177
189
|
end
|
|
178
190
|
|
|
179
|
-
def
|
|
180
|
-
|
|
191
|
+
def param_name
|
|
192
|
+
options[:as] || name
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def apply(context, relation)
|
|
196
|
+
data.is_a?(Proc) ? data.call(context, relation) : relation.public_send(name)
|
|
181
197
|
end
|
|
182
198
|
end
|
|
183
199
|
end
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
class String
|
|
2
2
|
def no_html
|
|
3
|
-
|
|
4
|
-
str.gsub!(/<br\/?>/, ' ')
|
|
5
|
-
str.gsub!(/<\/?[^>]*>/, '')
|
|
6
|
-
str.strip!
|
|
7
|
-
str.gsub!(' ', ' ')
|
|
8
|
-
str
|
|
3
|
+
self.dup.gsub(/<br\/?>/, ' ').gsub(/<\/?[^>]*>/, '').strip.gsub(' ', ' ').gsub('>', '>').gsub('<', '<')
|
|
9
4
|
end
|
|
10
5
|
end
|
|
11
6
|
|