ab_admin 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/ab_admin/components/admin_assets.js.coffee +6 -2
  3. data/app/assets/javascripts/ab_admin/components/base_assets.js.coffee +9 -0
  4. data/app/assets/javascripts/ab_admin/components/gmaps.js.coffee +1 -1
  5. data/app/assets/javascripts/ab_admin/components/in_place_edit.js.coffee +6 -0
  6. data/app/assets/javascripts/ab_admin/components/select2_bridge.js.coffee +2 -2
  7. data/app/assets/javascripts/ab_admin/core/batch_actions.js.coffee +52 -12
  8. data/app/assets/javascripts/ab_admin/core/init.js.coffee +2 -0
  9. data/app/assets/javascripts/ab_admin/core/pjax.js.coffee +3 -2
  10. data/app/assets/javascripts/ab_admin/core/ui_utils.js.coffee +3 -4
  11. data/app/assets/stylesheets/ab_admin/bootstrap_and_overrides.scss +4 -0
  12. data/app/assets/stylesheets/ab_admin/components/_colored_tabs.scss +4 -0
  13. data/app/assets/stylesheets/ab_admin/components/_form.scss +36 -3
  14. data/app/controllers/admin/admin_comments_controller.rb +4 -0
  15. data/app/controllers/admin/assets_controller.rb +5 -2
  16. data/app/controllers/admin/base_controller.rb +50 -41
  17. data/app/controllers/admin/locators_controller.rb +1 -1
  18. data/app/controllers/admin/manager_controller.rb +32 -3
  19. data/app/controllers/admin/settings_controller.rb +2 -3
  20. data/app/controllers/admin/static_pages_controller.rb +5 -0
  21. data/app/controllers/admin/structures_controller.rb +10 -4
  22. data/app/controllers/admin/users_controller.rb +9 -2
  23. data/app/views/admin/base/_search_layout.html.slim +0 -1
  24. data/app/views/admin/base/index.html.slim +1 -2
  25. data/app/views/admin/fileupload/_container.html.slim +17 -10
  26. data/app/views/admin/shared/_content_actions.html.slim +18 -6
  27. data/app/views/admin/shared/_locale_tabs.html.slim +3 -3
  28. data/app/views/admin/structures/_form.html.slim +2 -1
  29. data/app/views/layouts/admin/_footer.html.slim +5 -4
  30. data/app/views/layouts/admin/application.html.slim +2 -0
  31. data/config/locales/ru.yml +1 -0
  32. data/config/routes.rb +17 -22
  33. data/lib/ab_admin.rb +11 -1
  34. data/lib/ab_admin/abstract_resource.rb +11 -2
  35. data/lib/ab_admin/carrierwave/base_uploader.rb +45 -25
  36. data/lib/ab_admin/carrierwave/file_size_validator.rb +0 -1
  37. data/lib/ab_admin/carrierwave/glue.rb +2 -4
  38. data/lib/ab_admin/concerns/admin_addition.rb +12 -4
  39. data/lib/ab_admin/concerns/deep_cloneable.rb +0 -1
  40. data/lib/ab_admin/concerns/fileuploads.rb +0 -1
  41. data/lib/ab_admin/concerns/headerable.rb +0 -4
  42. data/lib/ab_admin/concerns/nested_set.rb +2 -3
  43. data/lib/ab_admin/concerns/reloadable.rb +0 -2
  44. data/lib/ab_admin/concerns/silencer.rb +0 -3
  45. data/lib/ab_admin/concerns/utilities.rb +2 -4
  46. data/lib/ab_admin/concerns/validations.rb +1 -1
  47. data/lib/ab_admin/config/base.rb +26 -6
  48. data/lib/ab_admin/controllers/callbacks.rb +6 -6
  49. data/lib/ab_admin/controllers/head_options.rb +0 -1
  50. data/lib/ab_admin/controllers/tree.rb +0 -2
  51. data/lib/ab_admin/core_ext.rb +1 -1
  52. data/lib/ab_admin/core_ext/array.rb +0 -1
  53. data/lib/ab_admin/core_ext/hash.rb +11 -0
  54. data/lib/ab_admin/core_ext/string.rb +0 -1
  55. data/lib/ab_admin/devise.rb +1 -1
  56. data/lib/ab_admin/engine.rb +2 -1
  57. data/lib/ab_admin/hooks/globalize_locale_suffix_accessors.rb +17 -31
  58. data/lib/ab_admin/hooks/will_paginate_no_uri.rb +1 -1
  59. data/lib/ab_admin/i18n_tools/google_translate.rb +0 -1
  60. data/lib/ab_admin/i18n_tools/translate_app.rb +0 -1
  61. data/lib/ab_admin/menu/builder.rb +3 -2
  62. data/lib/ab_admin/menu/group.rb +3 -1
  63. data/lib/ab_admin/models/asset.rb +9 -6
  64. data/lib/ab_admin/models/header.rb +2 -3
  65. data/lib/ab_admin/models/locator.rb +1 -1
  66. data/lib/ab_admin/models/settings.rb +6 -6
  67. data/lib/ab_admin/models/structure.rb +0 -6
  68. data/lib/ab_admin/models/track.rb +12 -3
  69. data/lib/ab_admin/models/type_model.rb +0 -1
  70. data/lib/ab_admin/models/user.rb +0 -1
  71. data/lib/ab_admin/models/validations/all.rb +4 -0
  72. data/lib/ab_admin/models/validations/domain_name_validator.rb +9 -0
  73. data/lib/ab_admin/models/validations/email_validator.rb +9 -0
  74. data/lib/ab_admin/utils.rb +12 -4
  75. data/lib/ab_admin/utils/eval_helpers.rb +1 -1
  76. data/lib/ab_admin/utils/logger.rb +0 -2
  77. data/lib/ab_admin/utils/xls_document.rb +25 -6
  78. data/lib/ab_admin/version.rb +1 -1
  79. data/lib/ab_admin/views/admin_helpers.rb +5 -4
  80. data/lib/ab_admin/views/admin_navigation_helpers.rb +16 -5
  81. data/lib/ab_admin/views/form_builder.rb +41 -10
  82. data/lib/ab_admin/views/helpers.rb +0 -2
  83. data/lib/ab_admin/views/inputs/uploader_input.rb +1 -0
  84. data/lib/ab_admin/views/search_form_builder.rb +33 -7
  85. data/lib/generators/ab_admin/ckeditor_assets/ckeditor_assets_generator.rb +0 -1
  86. data/lib/generators/ab_admin/glob/glob_generator.rb +2 -2
  87. data/lib/generators/ab_admin/glob/templates/migration.erb +1 -1
  88. data/lib/generators/ab_admin/install/install_generator.rb +0 -1
  89. data/lib/generators/ab_admin/install/templates/config/seeds.rb +0 -2
  90. data/lib/generators/ab_admin/install/templates/helpers/admin/structures_helper.rb +1 -4
  91. data/lib/generators/ab_admin/install/templates/models/admin_comment.rb +1 -3
  92. data/lib/generators/ab_admin/install/templates/models/asset.rb +3 -5
  93. data/lib/generators/ab_admin/install/templates/models/header.rb +1 -5
  94. data/lib/generators/ab_admin/install/templates/models/static_page.rb +1 -4
  95. data/lib/generators/ab_admin/install/templates/models/structure.rb +1 -5
  96. data/lib/generators/ab_admin/install/templates/models/track.rb +1 -2
  97. data/lib/generators/ab_admin/install/templates/models/user.rb +1 -9
  98. data/lib/generators/ab_admin/install/templates/uploaders/attachment_file_uploader.rb +1 -1
  99. data/lib/generators/ab_admin/install/templates/uploaders/avatar_uploader.rb +1 -1
  100. data/lib/generators/ab_admin/install/templates/uploaders/picture_uploader.rb +1 -1
  101. data/lib/generators/ab_admin/model/templates/resource.erb +1 -0
  102. data/lib/generators/template.rb +39 -59
  103. metadata +38 -36
  104. data/lib/ab_admin/hooks/active_model_attr_accessible_few_roles.rb +0 -50
@@ -9,7 +9,7 @@ class ::Admin::LocatorsController < ::Admin::BaseController
9
9
  end
10
10
 
11
11
  def update
12
- if Locator.save(@file, {params[:edit_locale_name] => params[:locale_hash]})
12
+ if Locator.save(@file, {params[:edit_locale_name] => params.require(:locale_hash).permit!.to_h})
13
13
  flash[:notice] = I18n.t('flash.admin.locators.updated')
14
14
  redirect_to admin_locators_path
15
15
  else
@@ -18,6 +18,14 @@ class ::Admin::ManagerController < ::Admin::BaseController
18
18
 
19
19
  protected
20
20
 
21
+ def button_scopes
22
+ manager.scopes.map{|scope| [scope.name, scope.options] }
23
+ end
24
+
25
+ def with_scopes(relation)
26
+ manager.scopes.inject(relation) { |result, scope| scope.apply(result, params) }
27
+ end
28
+
21
29
  def begin_of_association_chain
22
30
  parent
23
31
  end
@@ -68,8 +76,9 @@ class ::Admin::ManagerController < ::Admin::BaseController
68
76
  manager.default_action_items_for(action_name.to_sym, for_resource) + manager.action_items_for(action_name.to_sym)
69
77
  end
70
78
 
71
- def apply_batch_action(item, batch_action)
72
- success = call_method_or_proc_on item, manager.batch_action_list.detect{|a| a.name == batch_action }.data, exec: false
79
+ def apply_batch_action(item, batch_action, *batch_params)
80
+ data = manager.batch_action_list.detect{|a| a.name == batch_action }.data
81
+ success = call_method_or_proc_on item, data, exec: false, attrs: batch_params
73
82
  track_action!("batch_#{batch_action}", item) if settings[:history]
74
83
  success
75
84
  end
@@ -115,9 +124,29 @@ class ::Admin::ManagerController < ::Admin::BaseController
115
124
  end
116
125
  end
117
126
 
127
+ def permitted_params
128
+ attrs = case manager.permitted_params
129
+ when Proc then
130
+ instance_exec(&manager.permitted_params)
131
+ else
132
+ Array(manager.permitted_params)
133
+ end
134
+
135
+ resource_params = params[resource_class.model_name.param_key]
136
+ return {} unless resource_params
137
+ if attrs.first == :all
138
+ resource_params.permit!
139
+ else
140
+ attrs = attrs + AbAdmin.default_permitted_params
141
+ resource_params.permit(*attrs)
142
+ end
143
+ end
144
+
118
145
  def preview_resource_path(item)
119
146
  return unless manager.preview_path
120
- manager.preview_path.is_a?(Proc) ? instance_exec(item, &manager.preview_path) : send(manager.preview_path, item)
147
+ I18n.with_locale I18n.default_locale do
148
+ manager.preview_path.is_a?(Proc) ? instance_exec(item, &manager.preview_path) : send(manager.preview_path, item)
149
+ end
121
150
  end
122
151
 
123
152
  def admin_partial_name(builder)
@@ -4,9 +4,9 @@ class ::Admin::SettingsController < ::Admin::BaseController
4
4
  defaults resource_class: Settings
5
5
 
6
6
  def update
7
- Settings.instance.save(params[:settings])
7
+ Settings.instance.save(params.require(:settings).permit!.to_h)
8
8
  Settings.reload_checker.expire
9
- redirect_to :back
9
+ redirect_back fallback_location: admin_root_url
10
10
  end
11
11
 
12
12
  def cache_clear
@@ -31,5 +31,4 @@ class ::Admin::SettingsController < ::Admin::BaseController
31
31
  def resource
32
32
  Settings.instance
33
33
  end
34
-
35
34
  end
@@ -11,4 +11,9 @@ class Admin::StaticPagesController < Admin::BaseController
11
11
  {}
12
12
  end
13
13
 
14
+ def permitted_params
15
+ attrs = [:structure_id, :title, :content, :kind, :is_visible,
16
+ *StaticPage.all_translated_attribute_names, *AbAdmin.default_permitted_params]
17
+ params[:static_page].try!(:permit, *attrs)
18
+ end
14
19
  end
@@ -3,15 +3,12 @@ class Admin::StructuresController < Admin::BaseController
3
3
 
4
4
  load_and_authorize_resource
5
5
 
6
- #has_scope :visible
7
- #has_scope :un_visible
8
-
9
6
  protected
10
7
 
11
8
  def resource_action_items
12
9
  edit_structure = AbAdmin::Config::ActionItem.new({}) { |r| link_to icon('wrench', true), edit_resource_path(r), class: 'btn btn-warning' }
13
10
  edit_static_page = AbAdmin::Config::ActionItem.new({}) do |r|
14
- link_to(icon('pencil', true), edit_structure_record_path(r), class: 'btn btn-primary') if r.structure_type.static_page?
11
+ link_to(icon('pencil', true), edit_structure_record_path(r), class: 'btn btn-primary') if r.structure_type.static_page? || r.structure_type.main?
15
12
  end
16
13
  [edit_static_page, edit_structure, :destroy, :show]
17
14
  end
@@ -23,4 +20,13 @@ class Admin::StructuresController < Admin::BaseController
23
20
  def settings
24
21
  {index_view: 'tree', default_order: 'lft'}
25
22
  end
23
+
24
+ def permitted_params
25
+ attrs = [:structure_type_id, :position_type_id, :parent_id, :title, :redirect_url, :is_visible,
26
+ :structure_type, :position_type,
27
+ *Structure.simple_slug_columns,
28
+ *AbAdmin.default_permitted_params,
29
+ *Structure.all_translated_attribute_names, header_attributes: [:id, *Header.all_translated_attribute_names]]
30
+ params[:structure].try!(:permit, *attrs)
31
+ end
26
32
  end
@@ -3,12 +3,12 @@ class Admin::UsersController < Admin::BaseController
3
3
 
4
4
  def activate
5
5
  resource.activate!
6
- redirect_to :back
6
+ redirect_back fallback_location: admin_users_url
7
7
  end
8
8
 
9
9
  def suspend
10
10
  resource.suspend!
11
- redirect_to :back
11
+ redirect_back fallback_location: admin_users_url
12
12
  end
13
13
 
14
14
  private
@@ -46,4 +46,11 @@ class Admin::UsersController < Admin::BaseController
46
46
  resource
47
47
  end
48
48
 
49
+ def permitted_params
50
+ attrs = [:password, :password_confirmation, :email, :remember_me,
51
+ :login, :first_name, :last_name, :patronymic, :phone, :skype, :web_site, :address, :birthday,
52
+ :time_zone, :locale, :bg_color, :gender, *AbAdmin.default_permitted_params]
53
+ attrs << [:user_role_id] if admin?
54
+ params[:user].try!(:permit, *attrs)
55
+ end
49
56
  end
@@ -1,6 +1,5 @@
1
1
  #toggle_sidebar_off.btn.btn-large = icon('chevron-left')
2
2
  #toggle_sidebar_on.btn.btn-large = icon('chevron-right')
3
- h3= t('admin.search.title')
4
3
  = search_admin_form_for @search, url: collection_path do |f|
5
4
  = render 'search_form', f: f
6
5
  br
@@ -10,8 +10,7 @@
10
10
  .btn-toolbar.pull-right.pjax_links
11
11
  .btn-group
12
12
  - per_page_variants.each do |c|
13
- a.btn.per_page data-val=c href=url_for(params.merge(per_page: c)) class=('active' if c == collection.per_page) = c
13
+ a.btn.per_page data-val=c href=url_for(params_for_links.merge(per_page: c)) class=('active' if c == collection.per_page) = c
14
14
 
15
15
  - if pjax? && flash.present?
16
16
  script type='text/javascript' = render partial: 'admin/shared/flash', formats: :js, local_assigns: {flash: flash}
17
-
@@ -1,15 +1,22 @@
1
1
  .fileupload id=options[:container_id] class=options[:container_class]
2
2
  = options[:error]
3
3
  .fileupload-list.clearfix= render partial: asset_template, collection: assets
4
- .fileupload-upload
5
- .fileupload-button.pull-left
6
- .btn= options[:button_title] || I18n.t("admin.fileupload.button#{'s' if options[:multiple]}")
7
- = file_field_tag 'data', multiple: options[:multiple]
8
- .fileupload-edit-button.btn.pull-left= t('admin.actions.edit.link')
4
+ - unless options[:disabled]
5
+ .fileupload-upload
6
+ .fileupload-button.pull-left
7
+ .btn= options[:button_title] || I18n.t("admin.fileupload.button#{'s' if options[:multiple]}")
8
+ = file_field_tag 'data', multiple: options[:multiple]
9
+ .fileupload-edit-button.btn.pull-left= t('admin.actions.edit.link')
9
10
 
10
- .fileupload-info
11
- - if options[:extensions]
12
- .fileupload-info-extensions= options[:extensions].join(', ')
13
- .fileupload-info-max_size== "#{t('admin.fileupload.max_size')}: <b>#{options[:max_size]}</b> MB"
11
+ .fileupload-info
12
+ - if options[:extensions]
13
+ .fileupload-info-extensions= options[:extensions].join(', ')
14
+ .fileupload-info-max_size== "#{t('admin.fileupload.max_size')}: <b>#{options[:max_size]}</b> MB"
14
15
 
15
- = init_js("new AdminAssets(#{js_options.to_json})")
16
+ javascript:
17
+ if (document.readyState == 'complete') {
18
+ new AdminAssets(#{{js_options.to_json}});
19
+ }
20
+ else {
21
+ $(function(){new AdminAssets(#{{js_options.to_json}});});
22
+ }
@@ -7,12 +7,24 @@
7
7
  ul.dropdown-menu
8
8
  - batch_action_list.each do |batch_action|
9
9
  li
10
- a.batch_action_link href='#' data-action=batch_action.name data-confirm=batch_action.confirm = batch_action.title
10
+ a.batch_action_link(
11
+ href='#'
12
+ data-form=batch_action.form
13
+ data-action=batch_action.name
14
+ data-confirm=batch_action.confirm
15
+ )
16
+ = batch_action.title
11
17
  - unless button_scopes.blank?
12
18
  .btn-group.pjax_links
13
19
  - button_scopes.each do |name, opts|
14
- - active = params[opts[:as]]
15
- a.btn href=url_for(opts[:as] => (active ? nil : 1)) class=('active' if active) = t "admin.scopes.#{name}", default: name
20
+ - param_name = opts[:as] || name
21
+ - active = params[param_name]
22
+ a.btn href=url_for(param_name => (active ? nil : 1)) class=('active' if active)
23
+ = t "admin.scopes.#{name}", default: name.to_s.titleize
24
+ - if opts[:badge]
25
+ - scope_count = resource_class.send(name).count
26
+ - unless scope_count.zero?
27
+ span.badge< class=("badge-#{opts[:badge][:type] || 'important'}") = scope_count
16
28
 
17
29
  a.btn.pull-left#columns_hider_show href="#columns_hider" data-toggle='modal' = t 'admin.columns_hider.button'
18
30
 
@@ -29,9 +41,9 @@
29
41
  .btn-group.downloads
30
42
  = icon('download-alt')
31
43
  /- %w(csv xls json).each do |format|
32
- - %w(csv xls).each do |format|
33
- - next if format == 'xls' && !defined?(Mime::XLSX)
34
- = link_to format, params.merge(per_page: 10_000, format: format), id: "export_#{format}"
44
+ - %w(csv xlsx).each do |format|
45
+ - next if format == 'xlsx' && !Mime[:xlsx]
46
+ = link_to format, params_for_links.merge(per_page: 10_000, format: format), id: "export_#{format}"
35
47
 
36
48
  - if @search && settings[:sort_buttons]
37
49
  .btn-group
@@ -1,8 +1,8 @@
1
1
  .tabbable.locale_tabs
2
2
  ul.nav.nav-tabs
3
- - Globalize.available_locales.each_with_index do |l, i|
3
+ - locales.each_with_index do |l, i|
4
4
  li class=('active' if i.zero?)
5
5
  a data-toggle="tab" href="##{l}" class="ico_#{l}" = t("admin.langs.#{l}", default: l.to_s)
6
6
  .tab-content
7
- - Globalize.available_locales.each_with_index do |l, i|
8
- .tab-pane id=l class="tab_#{l} #{'active' if i.zero?}" = loc_html[l]
7
+ - locales.each_with_index do |l, i|
8
+ .tab-pane id=l class="tab_#{l} #{'active' if i.zero?}" = locale_html[l]
@@ -3,7 +3,8 @@
3
3
  = f.input :title, locale: l
4
4
  = f.input :redirect_url, locale: l, as: :string
5
5
 
6
- = f.input :slug
6
+ - Structure.simple_slug_columns.each do |column|
7
+ = f.input column
7
8
  - if @structure.moveable?
8
9
  = f.input :parent, as: :tree_select
9
10
  = f.input :structure_type_id, collection: StructureType.all
@@ -1,7 +1,8 @@
1
- footer
2
- ' Powered by
3
- a href='https://github.com/leschenko/ab_admin' target='_blank' = "AbAdmin #{AbAdmin::VERSION}"
4
- .muted.footer-notes= AbAdmin.footer_notes
1
+ - if AbAdmin.footer
2
+ footer
3
+ ' Powered by
4
+ a href='https://github.com/leschenko/ab_admin' target='_blank' = "AbAdmin #{AbAdmin::VERSION}"
5
+ .muted.footer-notes= AbAdmin.footer_notes
5
6
 
6
7
  = cache [I18n.locale, 'admin', 'footer'] do
7
8
  = render 'admin/fileupload/asset_templates'
@@ -8,6 +8,8 @@ html id="controller_#{controller_name}"
8
8
  = include_fv
9
9
  = javascript_include_tag 'ab_admin/application'
10
10
  = csrf_meta_tags
11
+ - if AbAdmin.favicon_path
12
+ link rel="icon" type="image/x-icon" href=AbAdmin.favicon_path
11
13
  = yield(:head)
12
14
  body id="action_#{action_name}" class="resource_#{resource_collection_name} #{AbAdmin.body_css_class}"
13
15
  #wrap
@@ -110,6 +110,7 @@ ru:
110
110
  form:
111
111
  cancel: Отмена
112
112
  save: Сохранить
113
+ saving: Сохранение
113
114
  save_and_add_another: Сохранить & новый
114
115
  save_and_edit: Сохранить & редактировать
115
116
  save_and_edit_next: Сохранить и след.
@@ -1,7 +1,6 @@
1
1
  Rails.application.routes.draw do
2
-
3
2
  namespace :admin do
4
- root to: 'dashboards#index'
3
+ root to: 'dashboards#index', as: :root
5
4
  get 'dashboards', as: 'dashboards'
6
5
 
7
6
  resources :structures do
@@ -33,27 +32,23 @@ Rails.application.routes.draw do
33
32
 
34
33
  post 'translate' => AbAdmin::I18nTools::TranslateApp
35
34
 
36
- controller 'manager', constraints: {format: /(html|js|json|xml|csv|xls|xlsx)/} do
37
- scope '(/:parent_resource/:parent_resource_id)/:model_name' do
38
- get '/new', action: :new, as: 'new'
39
- post '/batch', action: :batch, as: 'batch'
40
- post '/rebuild', action: :rebuild, as: 'rebuild'
41
- match '/custom_action', action: :custom_action, as: 'collection_action', via: :all
42
-
43
- scope ':id' do
44
- get '/edit', action: :edit, as: 'edit'
45
- get '/history', action: :history, as: 'history'
46
- match '/custom_action', action: :custom_action, as: 'member_action', via: :all
47
- get '/', action: :show, as: 'show'
48
- patch '/', action: :update, as: 'update'
49
- delete '/', action: :destroy, as: 'destroy'
50
- end
51
-
52
- get '/', action: :index, as: 'index'
53
- post '/', action: :create, as: 'create'
35
+ scope '(/:parent_resource/:parent_resource_id)/:model_name', controller: 'manager', constraints: {format: /(html|js|json|xml|csv|xls|xlsx)/} do
36
+ get '/new', action: :new, as: 'new'
37
+ post '/batch', action: :batch, as: 'batch'
38
+ post '/rebuild', action: :rebuild, as: 'rebuild'
39
+ match '/custom_action', action: :custom_action, as: 'collection_action', via: :all
40
+
41
+ scope ':id' do
42
+ get '/edit', action: :edit, as: 'edit'
43
+ get '/history', action: :history, as: 'history'
44
+ match '/custom_action', action: :custom_action, as: 'member_action', via: :all
45
+ get '/', action: :show, as: 'show'
46
+ patch '/', action: :update, as: 'update'
47
+ delete '/', action: :destroy, as: 'destroy'
54
48
  end
55
- end
56
49
 
50
+ get '/', action: :index, as: 'index'
51
+ post '/', action: :create, as: 'create'
52
+ end
57
53
  end
58
-
59
54
  end
@@ -8,6 +8,9 @@ require 'ab_admin/core_ext'
8
8
  require 'ab_admin/engine'
9
9
 
10
10
  module AbAdmin
11
+ DOMAINNAME_REGEXP = /\A(?:[0-9a-z]\.|[0-9a-z][0-9a-z\-]*[0-9a-z]+\.)+[a-z]{2,6}\z/
12
+ EMAIL_REGEXP = /\A[_A-Za-z0-9\-\+]+(?:\.[_A-Za-z0-9\-\+]+)*@(?:[0-9a-z]\.|[0-9a-z][0-9a-z\-]*[0-9a-z]+\.)+[a-z]{2,6}\z/
13
+
11
14
  autoload :Utils, 'ab_admin/utils'
12
15
  autoload :Devise, 'ab_admin/devise'
13
16
  autoload :AbstractResource, 'ab_admin/abstract_resource'
@@ -134,6 +137,8 @@ module AbAdmin
134
137
 
135
138
  mattr_accessor :body_css_class
136
139
 
140
+ mattr_accessor :favicon_path
141
+
137
142
  mattr_accessor :devise_layout
138
143
  @@devise_layout = 'admin/devise'
139
144
 
@@ -152,6 +157,9 @@ module AbAdmin
152
157
  mattr_accessor :test_settings
153
158
  @@test_settings = {}
154
159
 
160
+ mattr_accessor :footer
161
+ @@footer = true
162
+
155
163
  mattr_accessor :footer_notes
156
164
 
157
165
  mattr_accessor :default_url_options
@@ -179,12 +187,14 @@ module AbAdmin
179
187
  mattr_accessor :per_page_variants
180
188
  @@per_page_variants = [50, 100, 500, 1000]
181
189
 
190
+ mattr_accessor :default_permitted_params
191
+ @@default_permitted_params = [:fileupload_guid]
192
+
182
193
  extend Utils
183
194
 
184
195
  def self.setup
185
196
  yield self
186
197
  end
187
-
188
198
  end
189
199
 
190
200
 
@@ -8,7 +8,7 @@ module AbAdmin
8
8
 
9
9
  attr_accessor :model, :table, :search, :export, :form, :modal_form, :show, :preview_path, :actions, :custom_settings,
10
10
  :batch_action_list, :action_items, :disabled_action_items, :resource_action_items, :tree_node_renderer,
11
- :parent_resources, :custom_actions
11
+ :parent_resources, :custom_actions, :permitted_params, :scopes
12
12
 
13
13
  def initialize
14
14
  @actions = ACTIONS
@@ -20,6 +20,7 @@ module AbAdmin
20
20
  @action_items_for = {}
21
21
  @parent_resources = []
22
22
  @custom_actions = []
23
+ @scopes = []
23
24
  @model = self.class.name.sub('AbAdmin', '').safe_constantize
24
25
  add_admin_addition_to_model
25
26
  end
@@ -58,6 +59,10 @@ module AbAdmin
58
59
  instance.preview_path = block_given? ? block : value
59
60
  end
60
61
 
62
+ def permitted_params(*values, &block)
63
+ instance.permitted_params = block_given? ? block : values
64
+ end
65
+
61
66
  def actions(*actions_to_keep)
62
67
  instance.actions = begin
63
68
  options = actions_to_keep.extract_options!
@@ -123,6 +128,10 @@ module AbAdmin
123
128
  def collection_action(name, options={}, &block)
124
129
  instance.custom_actions << AbAdmin::Config::CustomAction.new(name, options.merge(collection: true), &block)
125
130
  end
131
+
132
+ def scope(name, options={}, &block)
133
+ instance.scopes << AbAdmin::Config::Scope.new(name, options, &block)
134
+ end
126
135
  end
127
136
 
128
137
  def export
@@ -164,4 +173,4 @@ module AbAdmin
164
173
  model.included_modules.include?(module_constant)
165
174
  end
166
175
  end
167
- end
176
+ end
@@ -1,18 +1,16 @@
1
- # encoding: utf-8
2
1
  require 'mime/types'
3
2
  require 'mini_magick'
4
3
  require 'carrierwave/processing/mini_magick'
5
- require 'carrierwave/processing/mime_types'
6
4
 
7
5
  module AbAdmin
8
6
  module CarrierWave
9
7
  class BaseUploader < ::CarrierWave::Uploader::Base
10
8
  include ::CarrierWave::MiniMagick
11
- include ::CarrierWave::MimeTypes
12
9
  include AbAdmin::Utils::EvalHelpers
13
10
 
14
- class_attribute :transliterate
11
+ class_attribute :transliterate, :human_filenames
15
12
  self.transliterate = true
13
+ self.human_filenames = true
16
14
 
17
15
  attr_accessor :internal_identifier
18
16
 
@@ -20,8 +18,6 @@ module AbAdmin
20
18
 
21
19
  storage :file
22
20
 
23
- process :set_content_type
24
-
25
21
  with_options if: :image? do |img|
26
22
  img.process :strip
27
23
  img.process cropper: lambda { |model| model.cropper_geometry }
@@ -30,19 +26,35 @@ module AbAdmin
30
26
 
31
27
  process :set_model_info
32
28
 
29
+ def strict_filename(for_file=filename)
30
+ "#{version_name || secure_token}#{File.extname(for_file).downcase}"
31
+ end
32
+
33
33
  def save_original_name(file)
34
34
  model.original_name ||= file.original_filename if file.respond_to?(:original_filename)
35
35
  end
36
36
 
37
+ def base_filename_part
38
+ if version_name
39
+ version_name.to_s.start_with?('retina_') ? "#{version_name.to_s.sub(/^retina_/, '')}@2x" : version_name.to_s
40
+ else
41
+ secure_token
42
+ end
43
+ end
44
+
37
45
  def full_filename(for_file=filename)
38
- ext = File.extname(for_file)
46
+ human_filenames ? human_full_filename(for_file) : strict_filename(for_file)
47
+ end
48
+
49
+ def human_full_filename(for_file=filename)
50
+ ext = File.extname(for_file).downcase
39
51
  human_filename_part = for_file.chomp(ext)
40
- tech_filename_part = "#{version_name || secure_token}#{ext}"
52
+ tech_filename_part = "#{base_filename_part}#{ext}"
41
53
  human_filename_part == secure_token ? tech_filename_part : "#{human_filename_part}_#{tech_filename_part}"
42
54
  end
43
55
 
44
56
  def full_original_filename
45
- "#{version_name || secure_token}#{File.extname(store_filename)}"
57
+ "#{base_filename_part}#{File.extname(store_filename)}"
46
58
  end
47
59
 
48
60
  # use secure token in the filename for non processed image
@@ -60,7 +72,7 @@ module AbAdmin
60
72
  alias_method :store_filename, :filename
61
73
 
62
74
  def filename
63
- internal_identifier || model.send("#{mounted_as}_file_name") || (store_filename && "#{secure_token}#{File.extname(store_filename)}")
75
+ internal_identifier || model.send("#{mounted_as}_file_name") || (store_filename && "#{secure_token}#{File.extname(store_filename).downcase}")
64
76
  end
65
77
 
66
78
  def write_internal_identifier(internal_identifier)
@@ -73,34 +85,42 @@ module AbAdmin
73
85
  def model_filename(base_filename, record)
74
86
  custom_file_name = model.build_filename(base_filename, record)
75
87
  return unless custom_file_name
76
- normalize_filename(custom_file_name) + File.extname(base_filename)
88
+ normalize_filename(custom_file_name) + File.extname(base_filename).downcase
77
89
  end
78
90
 
79
91
  def normalize_filename(raw_filename)
80
- I18n.transliterate(raw_filename).parameterize('_').gsub(/[\-_]+/, '_').downcase
92
+ parameterize_args = ActiveSupport::VERSION::MAJOR > 4 ? {separator: '_'} : '_'
93
+ I18n.transliterate(raw_filename).parameterize(parameterize_args).gsub(/[\-_]+/, '_').downcase
81
94
  end
82
95
 
83
96
  # rename files via move
84
97
  def rename_via_move(new_file_name)
85
- dir = File.dirname(path)
86
-
87
- moves = []
88
- versions.values.unshift(self).each do |v|
89
- from_path = File.join(dir, v.full_filename)
90
- to_path = File.join(dir, v.full_filename(new_file_name))
91
- return false if from_path == to_path || !File.exists?(from_path)
92
- moves << [from_path, to_path]
98
+ if human_filenames
99
+ dir = File.dirname(path)
100
+
101
+ moves = []
102
+ versions.values.unshift(self).each do |v|
103
+ from_path = File.join(dir, v.full_filename)
104
+ to_path = File.join(dir, v.full_filename(new_file_name))
105
+ next if from_path == to_path || !File.exists?(from_path)
106
+ moves << [from_path, to_path]
107
+ end
108
+ moves.each { |move| FileUtils.mv(*move) }
93
109
  end
94
- moves.each { |move| FileUtils.mv(*move) }
95
110
 
96
111
  write_internal_identifier new_file_name
97
112
  model.send("write_#{mounted_as}_identifier")
98
- retrieve_from_store!(new_file_name)
113
+ retrieve_from_store!(new_file_name) if human_filenames
114
+
99
115
  new_file_name
100
116
  end
101
117
 
102
118
  private :write_internal_identifier, :store_filename, :model_filename
103
119
 
120
+ def rmagick_included?
121
+ self.class.included_modules.map(&:to_s).include?('CarrierWave::RMagick')
122
+ end
123
+
104
124
  # prevent large number of subdirectories
105
125
  def store_dir
106
126
  str_id = model.id.to_s.rjust(4, '0')
@@ -126,7 +146,7 @@ module AbAdmin
126
146
 
127
147
  unless percentage.blank?
128
148
  manipulate! do |img|
129
- img.quality(percentage.to_s)
149
+ img.quality percentage.to_s
130
150
  img = yield(img) if block_given?
131
151
  img
132
152
  end
@@ -141,7 +161,7 @@ module AbAdmin
141
161
 
142
162
  unless degrees.blank?
143
163
  manipulate! do |img|
144
- img.rotate(degrees.to_s)
164
+ rmagick_included? ? img.rotate!(degrees.to_i) : img.rotate(degrees.to_s)
145
165
  img = yield(img) if block_given?
146
166
  img
147
167
  end
@@ -179,7 +199,7 @@ module AbAdmin
179
199
  end
180
200
 
181
201
  def image?(new_file = nil)
182
- (file || new_file).content_type.include? 'image'
202
+ AbAdmin.image_types.include?((file || new_file).content_type)
183
203
  end
184
204
 
185
205
  def dimensions