ab_admin 0.4.0 → 0.5.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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/ab_admin/components/in_place_edit.js.coffee +27 -12
  3. data/app/assets/javascripts/ab_admin/components/select2_bridge.js.coffee +39 -20
  4. data/app/assets/javascripts/ab_admin/core/columns_hider.js.coffee +4 -5
  5. data/app/assets/javascripts/ab_admin/inputs/datetime_input.js.coffee +3 -3
  6. data/app/assets/stylesheets/ab_admin/bootstrap_and_overrides.css.scss +5 -1
  7. data/app/assets/stylesheets/ab_admin/components/_columns_hider.css.scss +1 -1
  8. data/app/assets/stylesheets/ab_admin/components/_form.css.scss +1 -1
  9. data/app/controllers/admin/assets_controller.rb +4 -1
  10. data/app/controllers/admin/base_controller.rb +28 -10
  11. data/app/controllers/admin/locators_controller.rb +1 -1
  12. data/app/controllers/admin/manager_controller.rb +7 -2
  13. data/app/controllers/admin/static_pages_controller.rb +4 -5
  14. data/app/controllers/admin/structures_controller.rb +1 -1
  15. data/app/views/admin/base/create.js.erb +1 -1
  16. data/app/views/admin/base/edit.js.erb +16 -10
  17. data/app/views/admin/base/index.html.slim +2 -2
  18. data/app/views/admin/base/show.js.erb +2 -2
  19. data/app/views/admin/base/update.js.erb +12 -8
  20. data/app/views/admin/manager/_form.html.slim +4 -1
  21. data/app/views/admin/manager/_table.html.slim +2 -2
  22. data/app/views/admin/shared/_flash.html.slim +1 -1
  23. data/app/views/admin/structures/_form.html.slim +1 -1
  24. data/app/views/admin/users/_table.html.slim +1 -1
  25. data/config/locales/de.yml +18 -36
  26. data/config/locales/en.yml +20 -36
  27. data/config/locales/it.yml +12 -30
  28. data/config/locales/ru.yml +4 -17
  29. data/config/locales/uk.yml +301 -0
  30. data/lib/ab_admin.rb +1 -2
  31. data/lib/ab_admin/concerns/admin_addition.rb +1 -1
  32. data/lib/ab_admin/concerns/asset_human_names.rb +9 -1
  33. data/lib/ab_admin/concerns/utilities.rb +2 -6
  34. data/lib/ab_admin/controllers/tree.rb +2 -2
  35. data/lib/ab_admin/core_ext/array.rb +6 -5
  36. data/lib/ab_admin/hooks.rb +7 -32
  37. data/lib/ab_admin/hooks/{active_model_hooks.rb → active_model_attr_accessible_few_roles.rb} +12 -4
  38. data/lib/ab_admin/hooks/{globalize_hooks.rb → globalize_locale_suffix_accessors.rb} +1 -9
  39. data/lib/ab_admin/hooks/globalize_valid_locale.rb +9 -0
  40. data/lib/ab_admin/hooks/{paginate_hooks.rb → will_paginate_id_prefetch.rb} +7 -22
  41. data/lib/ab_admin/hooks/will_paginate_no_uri.rb +19 -0
  42. data/lib/ab_admin/i18n_tools/model_translator.rb +3 -2
  43. data/lib/ab_admin/menu/base_group.rb +3 -3
  44. data/lib/ab_admin/menu/item.rb +15 -4
  45. data/lib/ab_admin/models/asset.rb +6 -0
  46. data/lib/ab_admin/models/settings.rb +6 -6
  47. data/lib/ab_admin/models/user.rb +4 -0
  48. data/lib/ab_admin/utils.rb +16 -7
  49. data/lib/ab_admin/utils/xls_document.rb +9 -1
  50. data/lib/ab_admin/version.rb +1 -1
  51. data/lib/ab_admin/views/admin_helpers.rb +15 -11
  52. data/lib/ab_admin/views/admin_navigation_helpers.rb +11 -6
  53. data/lib/ab_admin/views/form_builder.rb +5 -1
  54. data/lib/ab_admin/views/search_form_builder.rb +1 -1
  55. data/lib/generators/ab_admin/glob/glob_generator.rb +6 -3
  56. data/lib/generators/ab_admin/install/install_generator.rb +1 -1
  57. data/lib/generators/ab_admin/install/templates/config/{unicorn_config.rb → unicorn/production.rb} +6 -9
  58. data/lib/generators/ab_admin/install/templates/script/unicorn.sh +7 -6
  59. data/lib/generators/template.rb +0 -1
  60. data/lib/tasks/assets.rake +7 -1
  61. metadata +34 -61
  62. data/app/assets/stylesheets/ab_admin/components/_text_styles.css.scss +0 -47
  63. data/lib/ab_admin/views/inputs/capture_block_input.rb +0 -16
@@ -54,11 +54,12 @@ class Array
54
54
  !(self & other).empty?
55
55
  end
56
56
 
57
- def to_hash
58
- h = {}
59
- each { |k, v| h[k] = v }
60
- h
61
- end
57
+ # def to_hash
58
+ # ActiveSupport::Deprecation.warn('Array#to_hash is deprecated, use Array#to_h or Hash[] instead')
59
+ # h = {}
60
+ # each { |k, v| h[k] = v }
61
+ # h
62
+ # end
62
63
 
63
64
  def val_detect(attr, val)
64
65
  detect{|v| v[attr] == val }
@@ -1,44 +1,19 @@
1
+ #
2
+ # ***** IMPORTANT *****
3
+ #
4
+ # This file contains some monkeypatching staff and is not required by default.
5
+ # Please, read code and comments before usage.
6
+ #
1
7
  Dir["#{File.dirname(__FILE__)}/hooks/*.rb"].sort.each do |path|
2
8
  require "ab_admin/hooks/#{File.basename(path, '.rb')}"
3
9
  end
4
10
 
5
- require 'i18n/core_ext/kernel/surpress_warnings'
6
-
7
11
  ActiveSupport::XmlMini.backend = 'Nokogiri'
8
12
 
9
13
  InheritedResources.flash_keys = Responders::FlashResponder.flash_keys = AbAdmin.flash_keys
10
14
  Responders::FlashResponder.namespace_lookup = true
11
15
 
12
16
  ::SimpleForm.wrapper_mappings ||= {}
13
- ::SimpleForm.wrapper_mappings[:capture_block] = ::SimpleForm.wrapper_mappings[:uploader] = AbAdmin::Views::ContentOnlyWrapper.instance
17
+ ::SimpleForm.wrapper_mappings[:uploader] = AbAdmin::Views::ContentOnlyWrapper.instance
14
18
 
15
19
  CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:]\.\-\+]/
16
-
17
- Time::DATE_FORMATS[:api] = '%d.%m.%Y'
18
- Time::DATE_FORMATS[:path] = '%Y_%m_%d_%H_%M_%S'
19
- Time::DATE_FORMATS[:compare] = '%Y%m%d%H%M'
20
- Time::DATE_FORMATS[:compare_date] = Date::DATE_FORMATS[:compare_date] = '%Y%m%d'
21
-
22
- Kernel.suppress_warnings do
23
- # fixed in master branch
24
- Russian::LOCALIZE_MONTH_NAMES_MATCH = /(%d|%e|%-d)(.*)(%B)/ if defined? Russian
25
- end
26
-
27
- if defined?(Sunrise::FileUpload)
28
- Sunrise::FileUpload.setup do |config|
29
- config.base_path = Rails.root.to_s
30
- end
31
-
32
- Sunrise::FileUpload::Manager.before_create do |env, asset|
33
- asset.user = env['warden'].user if env['warden']
34
- end
35
- end
36
-
37
- if defined?(Globalize)
38
- module Globalize
39
- def self.valid_locale?(loc)
40
- return false unless loc
41
- available_locales.include?(loc.to_sym)
42
- end
43
- end
44
- end
@@ -1,3 +1,4 @@
1
+ # enable to pass few roles to `attr_accessible` method which is very useful in defining `default` and `admin` attributes
1
2
  module ActiveModel
2
3
  module MassAssignmentSecurity
3
4
  module ClassMethods
@@ -20,23 +21,30 @@ end
20
21
  module ActiveModel
21
22
  module MassAssignmentSecurity
22
23
  class Sanitizer
23
- def sanitize(attributes, authorizers)
24
- sanitized_attributes = attributes.reject { |key, value| authorizers.all? { |auth| auth.deny?(key) } }
25
- #debug_protected_attribute_removal(attributes, sanitized_attributes)
24
+
25
+ def sanitize(klass, attributes, authorizers)
26
+ rejected = []
27
+ sanitized_attributes = attributes.reject do |key, value|
28
+ rejected << key if authorizers.all? { |authorizer| authorizer.deny?(key) }
29
+ end
30
+ process_removed_attributes(klass, rejected) unless rejected.empty?
26
31
  sanitized_attributes
27
32
  end
33
+
28
34
  end
29
35
  end
30
36
  end
31
37
 
32
38
  module ActiveModel
33
39
  module MassAssignmentSecurity
40
+
34
41
  def sanitize_for_mass_assignment(attributes, roles = nil)
35
- _mass_assignment_sanitizer.sanitize(attributes, mass_assignment_authorizer(roles))
42
+ _mass_assignment_sanitizer.sanitize(self.class, attributes, mass_assignment_authorizer(roles))
36
43
  end
37
44
 
38
45
  def mass_assignment_authorizer(roles)
39
46
  Array(roles).map { |role| self.class.active_authorizer[role || :default] }
40
47
  end
48
+
41
49
  end
42
50
  end
@@ -1,12 +1,4 @@
1
- module Globalize
2
- mattr_accessor :available_locales
3
-
4
- def self.valid_locale?(loc)
5
- return false unless loc
6
- available_locales.include?(loc.to_sym)
7
- end
8
- end
9
-
1
+ # add accessors with locale suffix like `title_en`, `title_de`
10
2
  Globalize::ActiveRecord::ClassMethods.module_eval do
11
3
  def define_translations_reader_with_locale_suffix(name)
12
4
  define_translations_reader_without_locale_suffix(name)
@@ -0,0 +1,9 @@
1
+ # add `valid_locale?` method to validate locale with globalize
2
+ module Globalize
3
+ mattr_accessor :available_locales
4
+
5
+ def self.valid_locale?(loc)
6
+ return false unless loc
7
+ available_locales.include?(loc.to_sym)
8
+ end
9
+ end
@@ -1,8 +1,10 @@
1
- require 'will_paginate/view_helpers/action_view'
1
+ # add `:large` option with make pagination on large tables easier, because `SELECT *` is slow with large `OFFSET`:
2
+ # first it fetch ids of the records using `SELECT id`
3
+ # and in the second query it fetch records
2
4
  module WillPaginate
3
5
  module ActiveRecord
4
6
  module RelationMethods
5
- attr_accessor :paginate_limit, :paginate_offset, :paginate_ids
7
+ attr_accessor :paginate_limit, :paginate_offset
6
8
 
7
9
  def per_page(value = nil)
8
10
  if value.nil?
@@ -24,7 +26,7 @@ module WillPaginate
24
26
  module Pagination
25
27
  def paginate(options)
26
28
  options = options.dup
27
- pagenum = options.fetch(:page) { raise ArgumentError, ':page parameter required' }
29
+ page_number = options.fetch(:page) { raise ArgumentError, ':page parameter required' }
28
30
  per_page = options.delete(:per_page) || self.per_page
29
31
  total = options.delete(:total_entries)
30
32
  large = options.delete(:large)
@@ -32,7 +34,7 @@ module WillPaginate
32
34
  count_options = options.delete(:count)
33
35
  options.delete(:page)
34
36
 
35
- rel = limit(per_page.to_i).page(pagenum)
37
+ rel = limit(per_page.to_i).page(page_number)
36
38
  rel = rel.apply_finder_options(options) if options.any?
37
39
  rel.wp_count_options = count_options if count_options
38
40
  rel.total_entries = total.to_i unless total.blank?
@@ -51,21 +53,4 @@ module WillPaginate
51
53
  end
52
54
  end
53
55
  end
54
- end
55
-
56
- WillPaginate::ViewHelpers.pagination_options[:no_uri] = false
57
- WillPaginate::ActionView::LinkRenderer.class_exec do
58
- def url(page)
59
- @base_url_params ||= begin
60
- url_params = merge_get_params(default_url_params)
61
- merge_optional_params(url_params)
62
- end
63
-
64
- url_params = @base_url_params.dup
65
- add_current_page_param(url_params, page)
66
- url_params[param_name.to_sym] = nil if url_params[param_name.to_sym].to_i < 2
67
-
68
- link = @template.url_for(url_params)
69
- @options[:no_uri] ? link.split('?').first : link
70
- end
71
- end
56
+ end
@@ -0,0 +1,19 @@
1
+ # add `:no_uri` options to skip query params in pagination urls
2
+ require 'will_paginate/view_helpers/action_view'
3
+
4
+ WillPaginate::ViewHelpers.pagination_options[:no_uri] = false
5
+ WillPaginate::ActionView::LinkRenderer.class_exec do
6
+ def url(page)
7
+ @base_url_params ||= begin
8
+ url_params = merge_get_params(default_url_params)
9
+ merge_optional_params(url_params)
10
+ end
11
+
12
+ url_params = @base_url_params.dup
13
+ add_current_page_param(url_params, page)
14
+ url_params[param_name.to_sym] = nil if url_params[param_name.to_sym].to_i < 2
15
+
16
+ link = @template.url_for(url_params)
17
+ @options[:no_uri] ? link.split('?').first : link
18
+ end
19
+ end
@@ -35,10 +35,11 @@ module AbAdmin
35
35
  end
36
36
  if model.new.respond_to?("#{attr}_#{locale.to_s}".to_sym)
37
37
  @locales.each do |locale_1|
38
- o["#{attr}_#{locale_1.to_s}"] = "#{ha(model, attr, locale)} (#{I18n.t(locale_1, scope: [:attrs])})"
38
+ attr_suffix = I18n.t(locale_1, scope: [:attrs], default: locale_1.to_s.humanize)
39
+ o["#{attr}_#{locale_1.to_s}"] = "#{ha(model, attr, locale)} (#{attr_suffix})"
39
40
  end
40
41
  end
41
- end.sort.to_hash
42
+ end.sort.to_h
42
43
  end
43
44
  @models_i18n_hash[locale]['activerecord']['attributes'] = models_hash
44
45
  end
@@ -9,9 +9,9 @@ module AbAdmin
9
9
  end
10
10
 
11
11
  def model(model, options={})
12
- title = model.model_name.human(count: 9)
13
- path = options[:url] || "/admin/#{model.model_name.plural}"
14
- @menu_tree << Item.new(title, path, options)
12
+ title = options[:title] || model.model_name.human(count: 9)
13
+ url = options[:url] || "/admin/#{model.model_name.plural}"
14
+ @menu_tree << Item.new(title, url, options)
15
15
  end
16
16
 
17
17
  def group(title, options={}, &block)
@@ -3,9 +3,9 @@ module AbAdmin
3
3
  class Item
4
4
  include ::AbAdmin::Utils::EvalHelpers
5
5
 
6
- def initialize(title, path, options)
6
+ def initialize(title, url, options)
7
7
  @title = title.is_a?(Symbol) ? I18n.t(title, scope: [:admin, :navigation]) : title
8
- @path = path
8
+ @url = url
9
9
  @options = options
10
10
  end
11
11
 
@@ -13,11 +13,22 @@ module AbAdmin
13
13
  return if @options[:if] && !call_method_or_proc_on(template, @options[:if])
14
14
  return if @options[:unless] && call_method_or_proc_on(template, @options[:unless])
15
15
 
16
- active = template.request.path.split('/')[2] == @path.split('/')[2]
16
+ item_url = @url.is_a?(String) ? @url : call_method_or_proc_on(template, @url)
17
+ active = template.request.path.split('/')[2] == item_url.split('/')[2]
18
+
17
19
  <<-HTML.html_safe
18
- <li class="#{'active' if active}">#{template.link_to @title, @path, @options.except(:if, :unless)}</li>
20
+ <li class="#{'active' if active}">#{template.link_to title(template), item_url, @options.except(:if, :unless)}</li>
19
21
  HTML
20
22
  end
23
+
24
+ private
25
+
26
+ def title(template)
27
+ return @title unless @options[:badge_counter]
28
+ badge_counter = call_method_or_proc_on(template, @options[:badge_counter])
29
+ return @title if !badge_counter || badge_counter.zero?
30
+ "#{@title}&nbsp;<span class='badge badge-#{@options[:badge_type] || 'important'}'>#{badge_counter}</span>".html_safe
31
+ end
21
32
  end
22
33
  end
23
34
  end
@@ -129,6 +129,12 @@ module AbAdmin
129
129
  AbAdmin.full_url data.url(*args)
130
130
  end
131
131
 
132
+ def url_on_fly(version)
133
+ file_url = url(version)
134
+ data.recreate_versions!(version) unless Rails.root.join("public/#{file_url}").exist?
135
+ file_url
136
+ end
137
+
132
138
  def cropper_geometry=(value)
133
139
  geometry = (value || '').to_s.split(',')
134
140
 
@@ -6,8 +6,12 @@ module AbAdmin
6
6
  included do
7
7
  extend ActiveModel::Naming
8
8
  extend ActiveRecord::Translation
9
- class_attribute :base_class, :editable_paths
9
+ class_attribute :base_class, :base_paths, :editable_paths
10
10
  self.base_class = self
11
+ self.base_paths = [
12
+ Rails.root.join('config', 'settings', 'settings.yml'),
13
+ Rails.root.join('config', 'settings', "#{Rails.env}.yml")
14
+ ]
11
15
  self.editable_paths = [
12
16
  Rails.root.join('config', 'settings', "#{Rails.env}.local.yml"),
13
17
  Rails.root.join('config', 'settings', 'settings.local.yml')
@@ -33,11 +37,7 @@ module AbAdmin
33
37
  end
34
38
 
35
39
  def find_paths
36
- [
37
- Rails.root.join('config', 'settings', 'settings.yml'),
38
- Rails.root.join('config', 'settings', "#{Rails.env}.yml"),
39
- @editable_path
40
- ].find_all { |path| File.exists?(path) }
40
+ base_paths.dup.unshift(@editable_path).find_all { |path| File.exists?(path) }
41
41
  end
42
42
 
43
43
  def all
@@ -36,6 +36,10 @@ module AbAdmin
36
36
  unlock_access! if access_locked?
37
37
  end
38
38
 
39
+ def active?
40
+ active_for_authentication?
41
+ end
42
+
39
43
  def generate_password!
40
44
  raw_password = AbAdmin.test_env? ? '654321' : AbAdmin.friendly_token
41
45
  self.password = self.password_confirmation = raw_password
@@ -14,7 +14,7 @@ module AbAdmin
14
14
  def bm(message = 'Benchmarking', options = {})
15
15
  result = nil
16
16
  ms = Benchmark.ms { result = yield }
17
- Rails.logger.debug '%s (%.3fms)' % [message, ms]
17
+ (options[:logger] || Rails.logger).info '%s (%.3fms)' % [message, ms]
18
18
  result
19
19
  end
20
20
 
@@ -57,9 +57,9 @@ module AbAdmin
57
57
 
58
58
  # html like: '<!-- html comment --><script>script content</script><div>div content</div><p>p content</p>'
59
59
  # normalized to: "<p>div content</p><p>p content</p>"
60
- def normalize_html(raw_html)
61
- @@sanitizer ||= Sanitizer.new
62
- @@sanitizer.normalize_html(raw_html)
60
+ def normalize_html(raw_html, options = {}, &block)
61
+ @@sanitizer ||= Sanitizer.new(options)
62
+ @@sanitizer.normalize_html(raw_html, &block)
63
63
  end
64
64
 
65
65
  def url_helpers
@@ -86,11 +86,20 @@ module AbAdmin
86
86
  class Sanitizer
87
87
  include ActionView::Helpers::SanitizeHelper
88
88
 
89
+ CLEAN_HTML_COMMENTS_REGEXP = /(&lt;|<)\!--.*?--(&gt;|>)/m
90
+ CLEAN_LINE_BREAKS_REGEXP = /[^>]\r\n/
91
+
92
+ def initialize(options = {})
93
+ @options = options
94
+ end
95
+
89
96
  def normalize_html(raw_html)
90
97
  return '' if raw_html.blank?
91
- html = sanitize(raw_html.gsub(/<!--(.*?)-->[\n]?/m, ''))
98
+ cleaned_html = raw_html.gsub(CLEAN_HTML_COMMENTS_REGEXP, '')#.gsub(CLEAN_LINE_BREAKS_REGEXP, '<br/>')
99
+ html = sanitize(cleaned_html, @options[:sanitize] || {})
92
100
  doc = Nokogiri::HTML.fragment(html)
93
101
  #doc.xpath('comment()').each { |c| c.remove }
102
+ yield doc if block_given?
94
103
  doc.search('div').each { |el| el.name = 'p' }
95
104
  doc.to_html
96
105
  end
@@ -103,7 +112,7 @@ module AbAdmin
103
112
 
104
113
  def display_name(resource)
105
114
  return unless resource
106
- resource.send(display_name_method_for(resource))
115
+ resource.send(display_name_method_for(resource)).to_s.no_html
107
116
  end
108
117
 
109
118
  def safe_display_name(resource)
@@ -136,4 +145,4 @@ module AbAdmin
136
145
  SecureRandom.base64(16).tr('+/=', 'xyz').first(n)
137
146
  end
138
147
  end
139
- end
148
+ end
@@ -2,6 +2,14 @@ require 'ruby2xlsx'
2
2
 
3
3
  module AbAdmin
4
4
  module Utils
5
+ class Default
6
+ extend ActiveModel::Naming
7
+
8
+ def self.human_attribute_name(*)
9
+ ''
10
+ end
11
+ end
12
+
5
13
  class XlsDocument < Ruby2xlsx::Base
6
14
  include AbAdmin::Utils::EvalHelpers
7
15
 
@@ -65,7 +73,7 @@ module AbAdmin
65
73
  count += 1
66
74
  end
67
75
  else
68
- items = Array.wrap(@source)
76
+ items = @source.respond_to?(:to_a) ? @source.to_a : Array.wrap(@source)
69
77
  @klass ||= items.first.class unless items.empty?
70
78
  @klass ||= Default
71
79
 
@@ -1,3 +1,3 @@
1
1
  module AbAdmin
2
- VERSION = '0.4.0'
2
+ VERSION = '0.5.0'
3
3
  end
@@ -24,17 +24,21 @@ module AbAdmin
24
24
  def admin_editable(item, attr, options=nil)
25
25
  options = {} unless options.is_a?(Hash)
26
26
  options[:type] ||= 'select' if options[:source]
27
- options[:type] ||= case attr.to_s
28
- when /_at$/
29
- 'date'
30
- when /^is_/
31
- 'select'
32
- when /description|body|content/
33
- 'textarea'
34
- else
35
- 'text'
36
- end
37
- options[:source] ||= {'true' => 'yes', 'false' => 'no'} if options[:type] == 'select'
27
+
28
+ case attr.to_s
29
+ when /_at$/
30
+ options[:type] ||= 'date'
31
+ when /^is_/
32
+ options[:type] ||= 'select'
33
+ options[:source] ||= {1 => 'yes', 0 => 'no'}
34
+ options[:value] ||= item[attr] ? 1 : 0
35
+ options[:title] ||= item[attr] ? 'yes' : 'no'
36
+ when /description|body|content/
37
+ options[:type] ||= 'textarea'
38
+ else
39
+ options[:type] ||= 'text'
40
+ end
41
+
38
42
  data = {
39
43
  type: options[:type],
40
44
  source: options[:source].try(:to_json),