locomotive_cms 2.5.5 → 2.5.6.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -2
  3. data/README.textile +3 -3
  4. data/app/assets/images/locomotive/icons/flags/pt.png +0 -0
  5. data/app/assets/javascripts/locomotive/utils/aloha_settings.js.coffee +1 -1
  6. data/app/assets/javascripts/locomotive/views/current_site/edit_view.js.coffee +5 -0
  7. data/app/assets/stylesheets/locomotive/backoffice/menu/main.css.scss +1 -1
  8. data/app/controllers/locomotive/api/theme_assets_controller.rb +1 -1
  9. data/app/controllers/locomotive/public/content_entries_controller.rb +6 -11
  10. data/app/controllers/locomotive/public/pages_controller.rb +1 -1
  11. data/app/controllers/locomotive/public/sitemaps_controller.rb +1 -1
  12. data/app/models/locomotive/extensions/content_type/sync.rb +16 -5
  13. data/app/models/locomotive/extensions/page/tree.rb +7 -3
  14. data/app/models/locomotive/extensions/site/locales.rb +12 -9
  15. data/app/models/locomotive/site.rb +10 -0
  16. data/app/views/locomotive/current_site/_form.html.haml +1 -0
  17. data/config/locales/admin_ui.cs.yml +2 -0
  18. data/config/locales/admin_ui.de.yml +3 -2
  19. data/config/locales/admin_ui.en.yml +1 -0
  20. data/config/locales/admin_ui.es.yml +2 -1
  21. data/config/locales/admin_ui.et.yml +1 -0
  22. data/config/locales/admin_ui.fr.yml +2 -1
  23. data/config/locales/admin_ui.it.yml +23 -0
  24. data/config/locales/admin_ui.ja.yml +1 -0
  25. data/config/locales/admin_ui.nb.yml +1 -0
  26. data/config/locales/admin_ui.nl.yml +4 -0
  27. data/config/locales/admin_ui.pl.yml +1 -0
  28. data/config/locales/admin_ui.pt-BR.yml +6 -5
  29. data/config/locales/admin_ui.pt.yml +320 -0
  30. data/config/locales/admin_ui.ru.yml +1 -0
  31. data/config/locales/admin_ui.sk.yml +2 -0
  32. data/config/locales/admin_ui.sr.yml +1 -0
  33. data/config/locales/admin_ui.zh-CN.yml +1 -0
  34. data/config/locales/carrierwave.pt.yml +4 -0
  35. data/config/locales/default.pt.yml +212 -0
  36. data/config/locales/devise.pt.yml +62 -0
  37. data/config/locales/flash.pt.yml +106 -0
  38. data/config/locales/formtastic.pt.yml +70 -0
  39. data/config/routes.rb +5 -6
  40. data/features/api/authorization/theme_assets.feature +4 -4
  41. data/features/public/contact_form.feature +1 -1
  42. data/features/public/new_contact_form.feature +95 -0
  43. data/features/public/pages.feature +2 -2
  44. data/features/step_definitions/relationships_steps.rb +37 -34
  45. data/lib/generators/locomotive/install/install_generator.rb +2 -0
  46. data/lib/generators/locomotive/install/templates/README +3 -2
  47. data/lib/generators/locomotive/install/templates/devise.rb +175 -0
  48. data/lib/generators/locomotive/install/templates/dragonfly.rb +1 -1
  49. data/lib/generators/locomotive/install/templates/locomotive.rb +2 -2
  50. data/lib/locomotive.rb +9 -0
  51. data/lib/locomotive/action_controller/public_responder.rb +45 -28
  52. data/lib/locomotive/configuration.rb +2 -2
  53. data/lib/locomotive/liquid/drops/content_entry.rb +6 -8
  54. data/lib/locomotive/liquid/drops/site.rb +1 -5
  55. data/lib/locomotive/liquid/filters/translate.rb +1 -1
  56. data/lib/locomotive/liquid/tags/fetch_page.rb +14 -6
  57. data/lib/locomotive/liquid/tags/model_form.rb +75 -0
  58. data/lib/locomotive/middlewares.rb +5 -1
  59. data/lib/locomotive/middlewares/base.rb +45 -0
  60. data/lib/locomotive/middlewares/locale.rb +32 -0
  61. data/lib/locomotive/middlewares/locale_redirection.rb +46 -0
  62. data/lib/locomotive/middlewares/seo_trailing_slash.rb +7 -28
  63. data/lib/locomotive/middlewares/site.rb +26 -0
  64. data/lib/locomotive/regexps.rb +1 -1
  65. data/lib/locomotive/render.rb +22 -2
  66. data/lib/locomotive/routing.rb +1 -0
  67. data/lib/locomotive/routing/post_content_entry_constraint.rb +11 -0
  68. data/lib/locomotive/routing/site_dispatcher.rb +1 -12
  69. data/lib/locomotive/version.rb +1 -1
  70. data/spec/dummy/config/boot.rb +1 -1
  71. data/spec/dummy/config/initializers/dragonfly.rb +1 -1
  72. data/spec/dummy/config/initializers/locomotive.rb +2 -2
  73. data/spec/lib/locomotive/liquid/drops/content_entry_spec.rb +23 -18
  74. data/spec/lib/locomotive/liquid/drops/site_spec.rb +25 -15
  75. data/spec/lib/locomotive/liquid/tags/model_form_spec.rb +46 -0
  76. data/spec/lib/locomotive/routing/site_dispatcher_spec.rb +0 -41
  77. data/spec/models/locomotive/site_spec.rb +1 -1
  78. data/spec/requests/locale_redirection_spec.rb +109 -0
  79. data/spec/requests/locale_spec.rb +85 -0
  80. data/spec/requests/seo_trailing_slash_spec.rb +1 -1
  81. data/spec/requests/site_spec.rb +27 -0
  82. data/spec/support/factories.rb +6 -0
  83. data/spec/support/middlewares.rb +3 -0
  84. metadata +48 -10
@@ -6,7 +6,7 @@ Dragonfly.app.configure do
6
6
  convert_command: `which convert`.strip.presence || '/usr/local/bin/convert',
7
7
  identify_command: `which identify`.strip.presence || '/usr/local/bin/identify'
8
8
 
9
- protect_from_dos_attacks true
9
+ verify_urls true
10
10
 
11
11
  secret '<%= generate_secret %>'
12
12
 
@@ -23,11 +23,11 @@ Locomotive.configure do |config|
23
23
  # per_page: 10
24
24
  # }
25
25
 
26
- # default locale (for now, only en, de, fr, pl, pt-BR, it, nb, ja, zh-CN, cs, bg and sk are supported)
26
+ # default locale (for now, only en, de, fr, pl, pt, pt-BR, it, nb, ja, zh-CN, cs, bg and sk are supported)
27
27
  config.default_locale = :en
28
28
 
29
29
  # available locales suggested to "localize" a site. You will have to pick up at least one among that list.
30
- # config.site_locales = %w{en de fr pl pt-BR it nl nb es ru ja zh-CN cs bg sk sr}
30
+ # config.site_locales = %w{en de fr pl pt pt-BR it nl nb es ru ja zh-CN cs bg sk sr}
31
31
 
32
32
  # tell if logs are enabled. Useful for debug purpose.
33
33
  config.enable_logs = true
@@ -69,6 +69,9 @@ module Locomotive
69
69
  if ::Dragonfly::VERSION =~ /^0\.9\.([0-9]+)/
70
70
  Locomotive.log :error, "WARNING: Old Dragonfly config detected, image uploads might be broken. Use 'rails g locomotive:install' to get the latest configuration files."
71
71
  end
72
+
73
+ # avoid I18n warnings
74
+ I18n.enforce_available_locales = false
72
75
  end
73
76
 
74
77
  def self.add_middlewares
@@ -77,6 +80,12 @@ module Locomotive
77
80
  self.app_middleware.use '::Locomotive::Middlewares::SeoTrailingSlash'
78
81
 
79
82
  self.app_middleware.use '::Locomotive::Middlewares::InlineEditor'
83
+
84
+ self.app_middleware.use '::Locomotive::Middlewares::Site'
85
+
86
+ self.app_middleware.use '::Locomotive::Middlewares::Locale'
87
+
88
+ self.app_middleware.use '::Locomotive::Middlewares::LocaleRedirection'
80
89
  end
81
90
 
82
91
  def self.configure_multi_sites
@@ -6,48 +6,65 @@ module Locomotive
6
6
  if get?
7
7
  raise error
8
8
  elsif has_errors? && default_action
9
- # get the content entry from the controller
10
- entry = self.controller.instance_variable_get :@entry
11
-
12
- if navigation_location =~ %r(^http://)
13
- # simple redirection for outside urls
14
- redirect_to navigation_location
15
- else
16
- # render the locomotive page
17
- self.controller.send :render_locomotive_page, navigation_location_for_locomotive, {
18
- entry.content_type.slug.singularize => entry.to_presenter(include_errors: true).as_json
19
- }
20
- end
9
+ navigation_error_behavior
21
10
  else
22
- entry = self.controller.instance_variable_get :@entry
11
+ navigation_success_behavior
12
+ end
13
+ end
23
14
 
24
- self.controller.flash['submitted_entry_id'] = entry.try(:_id).try(:to_s)
15
+ def navigation_error_behavior
16
+ if error_location =~ %r(^http://)
17
+ # simple redirection for outside urls
18
+ redirect_to error_location
19
+ else
20
+ path = page_path ? page_path : extract_locale_and_path(error_location)
25
21
 
26
- # redirect to a locomotive page
27
- redirect_to navigation_location
22
+ # render the locomotive page
23
+ self.controller.send :render_locomotive_page, path, {
24
+ content_entry.content_type.slug.singularize => content_entry.to_presenter(include_errors: true).as_json
25
+ }
28
26
  end
29
27
  end
30
28
 
31
- def navigation_location_for_locomotive
32
- locale, location = self.extract_locale_and_location
29
+ def navigation_success_behavior
30
+ # store in session the newly created content entry
31
+ self.controller.flash['submitted_entry_id'] = self.content_entry.try(:_id).try(:to_s)
33
32
 
34
- if locale
35
- ::I18n.locale = ::Mongoid::Fields::I18n.locale = locale
36
- location
37
- else
38
- navigation_location
39
- end
33
+ # redirect to a locomotive page
34
+ redirect_to success_location
35
+ end
36
+
37
+ def error_location
38
+ callback_url(:error) || (page_path ? request.path : '/')
39
+ end
40
+
41
+ def success_location
42
+ callback_url(:success) || (page_path ? request.path : '/')
43
+ end
44
+
45
+ # get the content entry from the controller
46
+ def content_entry
47
+ self.controller.instance_variable_get :@entry
48
+ end
49
+
50
+ def page_path
51
+ self.controller.params[:path]
52
+ end
53
+
54
+ def callback_url(state)
55
+ self.controller.params[:"#{state}_callback"]
40
56
  end
41
57
 
42
58
  protected
43
59
 
44
- def extract_locale_and_location
60
+ def extract_locale_and_path(path)
45
61
  locales = self.controller.send(:current_site).locales.join('|')
46
62
 
47
- if navigation_location =~ /\/(#{locales})+\/(.+)/
48
- [$1, $2]
63
+ if path =~ /\/(#{locales})+\/(.+)/
64
+ ::I18n.locale = ::Mongoid::Fields::I18n.locale = $1
65
+ $2
49
66
  else
50
- nil
67
+ path
51
68
  end
52
69
  end
53
70
 
@@ -7,8 +7,8 @@ module Locomotive
7
7
  reserved_subdomains: %w{www admin email blog webmail mail support help site sites},
8
8
  # forbidden_paths: %w{layouts snippets stylesheets javascripts assets admin system api},
9
9
  reserved_slugs: %w{stylesheets javascripts assets admin locomotive images api pages edit},
10
- locales: %w{en de fr pl pt-BR it nl nb es ru et ja zh-CN cs bg sk sr},
11
- site_locales: %w{en de fr pl pt-BR it nl nb es ru et ja zh-CN cs bg sk sr},
10
+ locales: %w{en de fr pl pt pt-BR it nl nb es ru et ja zh-CN cs bg sk sr},
11
+ site_locales: %w{en de fr pl pt pt-BR it nl nb es ru et ja zh-CN cs bg sk sr},
12
12
  cookie_key: '_locomotive_session',
13
13
  enable_logs: false,
14
14
  enable_admin_ssl: false,
@@ -62,16 +62,14 @@ module Locomotive
62
62
  protected
63
63
 
64
64
  def filter_and_order_list(list)
65
- # filter ?
66
- if @context['with_scope']
67
- conditions = HashWithIndifferentAccess.new(@context['with_scope'])
68
- order_by = conditions.delete(:order_by).try(:split)
65
+ conditions, order_by = HashWithIndifferentAccess.new(_visible: true), nil
69
66
 
70
- list.filtered(conditions, order_by)
71
- else
72
- # no filter, default order
73
- list.ordered
67
+ if @context['with_scope']
68
+ conditions.merge!(@context['with_scope'])
69
+ order_by = conditions.delete(:order_by).try(:split)
74
70
  end
71
+
72
+ list.filtered(conditions, order_by)
75
73
  end
76
74
 
77
75
  end
@@ -20,11 +20,7 @@ module Locomotive
20
20
  protected
21
21
 
22
22
  def scoped_pages
23
- if @context['with_scope']
24
- @_source.pages.where(@context['with_scope'])
25
- else
26
- @_source.pages
27
- end
23
+ @_source.ordered_pages(@context['with_scope'])
28
24
  end
29
25
 
30
26
  end
@@ -15,7 +15,7 @@ module Locomotive
15
15
  locale ||= I18n.locale.to_s
16
16
 
17
17
  if scope.blank?
18
- translation = Locomotive::Translation.where(key: input).first
18
+ translation = @context.registers[:site].translations.where(key: input).first
19
19
 
20
20
  # key not found
21
21
  return input if translation.nil?
@@ -1,10 +1,18 @@
1
1
  module Locomotive
2
2
  module Liquid
3
3
  module Tags
4
+
5
+ # Fetch a page from its handle and assign it to a liquid variable.
6
+ #
7
+ # Usage:
8
+ #
9
+ # {% fetch_page 'about_us' as a_page %}
10
+ # <p>{{ a_page.title }}</p>
11
+ #
4
12
  class FetchPage < ::Liquid::Tag
5
-
13
+
6
14
  Syntax = /(#{::Liquid::VariableSignature}+)\s+as\s+(#{::Liquid::VariableSignature}+)/
7
-
15
+
8
16
  def initialize(tag_name, markup, tokens, context)
9
17
  if markup =~ Syntax
10
18
  @handle = $1
@@ -12,16 +20,16 @@ module Locomotive
12
20
  else
13
21
  raise SyntaxError.new("Syntax Error in 'fetch_page' - Valid syntax: fetch_page page_handle as variable")
14
22
  end
15
-
23
+
16
24
  super
17
- end
18
-
25
+ end
26
+
19
27
  def render(context)
20
28
  context.scopes.last[@var] = context.registers[:site].pages.where(handle: @handle).first
21
29
  ''
22
30
  end
23
31
  end
24
-
32
+
25
33
  ::Liquid::Template.register_tag('fetch_page', FetchPage)
26
34
  end
27
35
  end
@@ -0,0 +1,75 @@
1
+ module Locomotive
2
+ module Liquid
3
+ module Tags
4
+
5
+ # Display the form html tag with the appropriate hidden fields in order to create
6
+ # a content entry from a public site.
7
+ # It handles callbacks, csrf and target url out of the box.
8
+ #
9
+ # Usage:
10
+ #
11
+ # {% model_form 'newsletter_addresses' %}
12
+ # <input type='text' name='content[email]' />
13
+ # <input type='submit' value='Add' />
14
+ # {% endform_form %}
15
+ #
16
+ # {% model_form 'newsletter_addresses', class: 'a-css-class', success: 'http://www.google.fr', error: '/error' %}...{% endform_form %}
17
+ #
18
+ class ModelForm < Solid::Block
19
+
20
+ tag_name :model_form
21
+
22
+ def display(*options, &block)
23
+ name = options.shift
24
+ options = options.shift || {}
25
+
26
+ form_attributes = { method: 'POST', enctype: 'multipart/form-data' }.merge(options.slice(:id, :class))
27
+
28
+ html_content_tag :form,
29
+ content_type_html(name) + csrf_html + callbacks_html(options) + yield,
30
+ form_attributes
31
+ end
32
+
33
+ def content_type_html(name)
34
+ html_tag :input, type: 'hidden', name: 'content_type_slug', value: name
35
+ end
36
+
37
+ def csrf_html
38
+ name = controller.send(:request_forgery_protection_token).to_s
39
+ value = controller.send(:form_authenticity_token)
40
+
41
+ html_tag :input, type: 'hidden', name: name, value: value
42
+ end
43
+
44
+ def callbacks_html(options)
45
+ options.slice(:success, :error).map do |(name, value)|
46
+ html_tag :input, type: 'hidden', name: "#{name}_callback", value: value
47
+ end.join('')
48
+ end
49
+
50
+ private
51
+
52
+ def controller
53
+ current_context.registers[:controller]
54
+ end
55
+
56
+ def html_content_tag(name, content, options = {})
57
+ "<#{name} #{inline_options(options)}>#{content}</#{name}>"
58
+ end
59
+
60
+ def html_tag(name, options = {})
61
+ "<#{name} #{inline_options(options)} />"
62
+ end
63
+
64
+ # Write options (Hash) into a string according to the following pattern:
65
+ # <key1>="<value1>", <key2>="<value2", ...etc
66
+ def inline_options(options = {})
67
+ return '' if options.empty?
68
+ (options.stringify_keys.to_a.collect { |a, b| "#{a}=\"#{b}\"" }).join(' ')
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+ end
75
+ end
@@ -1,5 +1,9 @@
1
1
  require 'rack/cache'
2
2
 
3
+ require 'locomotive/middlewares/base'
3
4
  require 'locomotive/middlewares/seo_trailing_slash'
4
5
  require 'locomotive/middlewares/inline_editor'
5
- require 'locomotive/middlewares/permalink'
6
+ require 'locomotive/middlewares/permalink'
7
+ require 'locomotive/middlewares/site'
8
+ require 'locomotive/middlewares/locale'
9
+ require 'locomotive/middlewares/locale_redirection'
@@ -0,0 +1,45 @@
1
+ module Locomotive
2
+ module Middlewares
3
+ class Base
4
+
5
+ protected
6
+
7
+ def is_backoffice?(request)
8
+ request.path.match(%r(^#{Locomotive.mounted_on}(/|$))) != nil
9
+ end
10
+
11
+ def is_assets?(request)
12
+ request.path.match(%r(^/assets(/|$))) != nil
13
+ end
14
+
15
+ # Create a 301 response and set it up accordingly.
16
+ #
17
+ # @params [ String ] url The url for the redirection
18
+ #
19
+ # @return [ Array ] It has the 3 parameters (status, header, body)
20
+ #
21
+ def redirect_to(url)
22
+ response = Rack::Response.new
23
+ response.redirect(url, 301) # moved permanently
24
+ response.finish
25
+ response.to_a
26
+ end
27
+
28
+ # Modify the fullpath according to the regexp/replacement
29
+ # and return the updated url
30
+ #
31
+ # @params [ Rack::Request ] request The base request
32
+ # @params [ Regexp ] regexp The regexp to apply to the fullpath
33
+ # @params [ String ] replacement The replacement string for the fullpath
34
+ #
35
+ # @return [ String ] The updated url
36
+ #
37
+ def modify_url(request, path)
38
+ url = "#{request.base_url}#{path}"
39
+ url += "?#{request.query_string}" unless request.query_string.empty?
40
+ url
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,32 @@
1
+ module Locomotive
2
+ module Middlewares
3
+ class Locale
4
+
5
+ def initialize(app, opts = {})
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ retrieve_and_set_locale(env)
11
+ @app.call(env)
12
+ end
13
+
14
+ def retrieve_and_set_locale(env)
15
+ site = env['locomotive.site']
16
+
17
+ if site.try(:localized?)
18
+ if env['PATH_INFO'] =~ %r{^/(#{site.locales.join('|')})+(\/|$)}
19
+ locale = $1
20
+ path = env['PATH_INFO'].gsub($1 + $2, '').gsub(/(\/_edit|\/_admin)$/, '')
21
+
22
+ Locomotive.log "[extract locale] locale = #{locale} / #{path}"
23
+
24
+ env['locomotive.locale'] = locale
25
+ env['locomotive.path'] = path
26
+ end
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,46 @@
1
+ module Locomotive
2
+ module Middlewares
3
+ class LocaleRedirection < Base
4
+
5
+ def initialize(app, opts = {})
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ if url = redirect_url(env)
11
+ redirect_to url
12
+ else
13
+ @app.call(env)
14
+ end
15
+ end
16
+
17
+ protected
18
+
19
+ def redirect_url(env)
20
+ request = Rack::Request.new(env)
21
+
22
+ site, locale = env['locomotive.site'], env['locomotive.locale']
23
+
24
+ if apply_redirection?(site, request)
25
+ segments = request.path.split '/'
26
+
27
+ if !locale && site.prefix_default_locale
28
+ # force locale in path by redirecting
29
+ segments.insert(1, "#{site.default_locale}")
30
+ modify_url(request, segments.join('/'))
31
+
32
+ elsif locale == site.default_locale && !site.prefix_default_locale
33
+ # strip locale
34
+ segments.delete_at(1)
35
+ modify_url(request, segments.join('/'))
36
+ end
37
+ end
38
+ end
39
+
40
+ def apply_redirection?(site, request)
41
+ site.try(:localized?) && request.get? && !is_backoffice?(request) && !is_assets?(request)
42
+ end
43
+
44
+ end
45
+ end
46
+ end