locomotivecms 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -3
  3. data/README.md +24 -30
  4. data/app/api/locomotive/api/entities/content_type_field_entity.rb +1 -1
  5. data/app/api/locomotive/api/forms/content_type_field_form.rb +1 -1
  6. data/app/api/locomotive/api/resources/content_type_resource.rb +2 -0
  7. data/app/assets/javascripts/locomotive/views/editable_elements/iframe_view.js.coffee +1 -1
  8. data/app/assets/javascripts/locomotive/views/editable_elements/page_view.js.coffee +4 -1
  9. data/app/assets/javascripts/locomotive/views/inputs/array_view.js.coffee +2 -2
  10. data/app/assets/stylesheets/locomotive/account.scss +1 -1
  11. data/app/assets/stylesheets/locomotive/account/_files.scss +2 -1
  12. data/app/assets/stylesheets/locomotive/account/_navigation.scss +2 -1
  13. data/app/assets/stylesheets/locomotive/account/_public.scss +22 -5
  14. data/app/assets/stylesheets/locomotive/account/_type.scss +5 -0
  15. data/app/assets/stylesheets/locomotive/live_editing_iframe.scss +1 -1
  16. data/app/controllers/locomotive/concerns/redirect_to_main_host_controller.rb +1 -1
  17. data/app/helpers/locomotive/custom_fields_helper.rb +5 -1
  18. data/app/inputs/locomotive/file_input.rb +1 -1
  19. data/app/models/locomotive/concerns/asset/checksum.rb +2 -3
  20. data/app/models/locomotive/concerns/page/redirect.rb +1 -1
  21. data/app/models/locomotive/concerns/site/access_points.rb +13 -0
  22. data/app/models/locomotive/editable_file.rb +1 -1
  23. data/app/models/locomotive/editable_model.rb +4 -0
  24. data/app/uploaders/locomotive/editable_file_uploader.rb +3 -1
  25. data/app/uploaders/locomotive/picture_uploader.rb +1 -1
  26. data/app/views/locomotive/editable_elements/_form.html.slim +8 -7
  27. data/app/views/locomotive/errors/404.html.slim +3 -5
  28. data/app/views/locomotive/errors/500.html.slim +3 -5
  29. data/app/views/locomotive/errors/no_site.html.slim +6 -11
  30. data/app/views/locomotive/layouts/account.html.slim +1 -1
  31. data/app/views/locomotive/layouts/error.html.slim +1 -2
  32. data/app/views/locomotive/sessions/new.html.slim +1 -1
  33. data/config/locales/simple_form.en.yml +1 -1
  34. data/config/routes.rb +4 -2
  35. data/lib/generators/locomotive/install/install_generator.rb +1 -1
  36. data/lib/generators/locomotive/install/templates/locomotive.rb +8 -0
  37. data/lib/locomotive/configuration.rb +2 -0
  38. data/lib/locomotive/middlewares/site.rb +1 -1
  39. data/lib/locomotive/mongoid.rb +0 -1
  40. data/lib/locomotive/regexps.rb +3 -3
  41. data/lib/locomotive/simple_form.rb +1 -0
  42. data/lib/locomotive/steam/middlewares/cache.rb +6 -1
  43. data/lib/locomotive/steam/middlewares/page_editing.rb +23 -1
  44. data/lib/locomotive/steam_adaptor.rb +1 -1
  45. data/lib/locomotive/version.rb +1 -1
  46. data/spec/dummy/config/initializers/locomotive.rb +4 -0
  47. data/spec/dummy/config/mongoid.yml +1 -0
  48. data/spec/models/locomotive/concerns/page/redirect_spec.rb +25 -0
  49. data/spec/models/locomotive/concerns/site/access_points_spec.rb +29 -0
  50. data/spec/requests/locomotive/site_spec.rb +11 -1
  51. data/spec/requests/locomotive/steam/cache_spec.rb +3 -2
  52. data/spec/support/capybara.rb +9 -6
  53. data/spec/support/features/session_helpers.rb +1 -0
  54. data/spec/support/features/site_helpers.rb +3 -0
  55. data/spec/support/mongoid.rb +1 -1
  56. metadata +8 -12
  57. data/app/assets/stylesheets/locomotive/components/_error.scss +0 -37
  58. data/app/assets/stylesheets/locomotive/error.scss +0 -12
  59. data/app/assets/stylesheets/locomotive/layouts/_error.scss +0 -33
  60. data/lib/locomotive/mongoid/presenter.rb +0 -76
@@ -9,5 +9,9 @@ module Locomotive
9
9
  self.content_type.name
10
10
  end
11
11
 
12
+ def content_type?
13
+ !content_type.nil?
14
+ end
15
+
12
16
  end
13
17
  end
@@ -12,7 +12,9 @@ module Locomotive
12
12
  end
13
13
 
14
14
  def image?
15
- self.file ? self.file.content_type : false
15
+ if self.file.exists?
16
+ self.file.content_type.start_with?('image')
17
+ end
16
18
  end
17
19
 
18
20
  end
@@ -10,7 +10,7 @@ module Locomotive
10
10
  end
11
11
 
12
12
  def image?
13
- self.file ? self.file.content_type : false
13
+ self.file.try(:exists?)
14
14
  end
15
15
 
16
16
  def store_dir
@@ -22,11 +22,12 @@
22
22
  = g.input :content, editable_element_input_options(editable_element, index, as: :select, collection: editable_element.options.map { |attributes| [attributes['text'], attributes['value']] })
23
23
 
24
24
  - when :editable_model
25
- fieldset.inputs
26
- .form-group.input.link.optional data-block=editable_element.block
27
- label.link.control-label.optional= editable_element_label(editable_element)
28
- - if editable_element.hint.present?
29
- span class="help-inline"= editable_element.hint
30
- span.form_wrapper
31
- = link_to t('.model.buttons.list'), content_entries_path(current_site, editable_element.content_type.slug), class: 'btn btn-primary btn-sm'
25
+ - if editable_element.content_type?
26
+ fieldset.inputs
27
+ .form-group.input.link.optional data-block=editable_element.block
28
+ label.link.control-label.optional= editable_element_label(editable_element)
29
+ - if editable_element.hint.present?
30
+ span class="help-inline"= editable_element.hint
31
+ span.form_wrapper
32
+ = link_to t('.model.buttons.list'), content_entries_path(current_site, editable_element.content_type.slug), class: 'btn btn-primary btn-sm'
32
33
 
@@ -1,9 +1,7 @@
1
1
  .public-box
2
2
  .public-intro
3
- h3.text-center
3
+ h3
4
+ i.fa.fa-exclamation-triangle
4
5
  == error_title
5
-
6
- br
7
-
8
- p.text-center
6
+ p
9
7
  == t('.message')
@@ -1,9 +1,7 @@
1
1
  .public-box
2
2
  .public-intro
3
- h3.text-center
3
+ h3
4
+ i.fa.fa-exclamation-triangle
4
5
  == error_title
5
-
6
- br
7
-
8
- p.text-center
6
+ p
9
7
  == t('.message')
@@ -2,15 +2,10 @@
2
2
 
3
3
  .public-box
4
4
  .public-intro
5
- h3.text-center
6
- == error_title
7
-
8
- br
9
-
10
- p.text-justify
5
+ h3
6
+ i.fa.fa-exclamation-triangle
7
+ = error_title
8
+ p
11
9
  == message
12
-
13
- br
14
-
15
- p.text-center.next
16
- = link_to t('.next').html_safe, link
10
+ br
11
+ = link_to t('.next').html_safe, link, class: 'btn btn-primary'
@@ -4,7 +4,7 @@ html xmlns='http://www.w3.org/1999/xhtml' lang=I18n.locale
4
4
  meta charset="utf-8"
5
5
  meta http-equiv="x-ua-compatible" content="ie=edge"
6
6
 
7
- title= escape_once(strip_tags(title) + " | Locomotive")
7
+ title= escape_once(strip_tags(title) + " | #{Locomotive.config.name}")
8
8
 
9
9
  meta name="viewport" content="width=device-width, initial-scale=1"
10
10
 
@@ -19,7 +19,6 @@ html xmlns='http://www.w3.org/1999/xhtml' lang=I18n.locale
19
19
  .public-container
20
20
  .public-wrapper
21
21
  = link_to root_path, class: 'brand-logo' do
22
- = image_tag 'locomotive/logo.png'
23
- span Locomotive
22
+ = image_tag 'locomotive/logo-white.png'
24
23
 
25
24
  = yield
@@ -20,5 +20,5 @@
20
20
  = f.actions do
21
21
  = f.button :submit, t('.submit'), class: 'btn btn-primary'
22
22
 
23
- - if current_site.nil?
23
+ - if current_site.nil? && Locomotive.config.enable_registration
24
24
  = link_to t('.sign_up').html_safe, sign_up_path, class: 'public-link'
@@ -94,7 +94,7 @@ en:
94
94
  meta_keywords: "Meta keywords used within the head tag of the page. They are separated by a comma. Required for SEO."
95
95
  meta_description: "Meta description used within the head tag of the page. Required for SEO."
96
96
  robots_txt: "Content of the <span class='code'>/robots.txt</span> file. Check the following <a href='http://www.w3.org/TR/html4/appendix/notes.html#h-B.4.1.1'>url</a> for more information."
97
- domains: "Add your domains just below. Then, register a CNAME DNS record pointing to <b>%{domain}</b>."
97
+ domains: "Add your domains just below. Documentation <a href=\"https://locomotive-v3.readme.io/docs/domains\">here</a> for more information."
98
98
  memberships: "You can invite other accounts to edit/manage the site."
99
99
  cache_enabled: "When enabled, your pages will be cached as long as the content doesn't change. Disabling cache per page is allowed."
100
100
  redirect_to_first_domain: "When enabled, requests made to any domains listed above will be redirected to the first domain."
data/config/routes.rb CHANGED
@@ -10,8 +10,10 @@ Locomotive::Engine.routes.draw do
10
10
  failure_app: 'Locomotive::Devise::FailureApp'
11
11
 
12
12
  devise_scope :locomotive_account do
13
- get 'sign_up' => 'registrations#new', as: :sign_up
14
- post 'sign_up' => 'registrations#create'
13
+ if Locomotive.config.enable_registration
14
+ get 'sign_up' => 'registrations#new', as: :sign_up
15
+ post 'sign_up' => 'registrations#create'
16
+ end
15
17
  get 'sign_in' => 'sessions#new', as: :sign_in
16
18
  delete 'sign_out' => 'sessions#destroy', as: :sign_out
17
19
  end
@@ -37,7 +37,7 @@ module Locomotive
37
37
  mount Locomotive::API.to_app => '/locomotive(/:site_handle)/api'
38
38
 
39
39
  # Render site
40
- mount Locomotive::Steam::Server.to_app => '/', anchor: false)
40
+ mount Locomotive::Steam.to_app => '/', anchor: false)
41
41
  end
42
42
 
43
43
  def enable_heroku
@@ -6,6 +6,9 @@ Locomotive.configure do |config|
6
6
  # list of forbidden handles for a site because there are in conflicts with internal resources.
7
7
  # config.reserved_site_handles = %w(sites my_account password sign_in sign_out)
8
8
 
9
+ # list of domains which can't be used by any Locomotive sites
10
+ # config.reserved_domains = []
11
+
9
12
  # configure how many items we display in sub menu in the "Models" section.
10
13
  config.ui = {
11
14
  per_page: 10
@@ -59,4 +62,9 @@ Locomotive.configure do |config|
59
62
 
60
63
  # Dragonfly within Steam uses it to generate the protective SHA
61
64
  # config.steam_image_resizer_secret = 'please change it'
65
+
66
+ # Indicate whether you want to allow users to register with the site. If set
67
+ # to false the registration page will not be shown. (Default: true)
68
+ # config.enable_registration = true
69
+
62
70
  end
@@ -9,6 +9,7 @@ module Locomotive
9
9
  # forbidden_paths: %w{layouts snippets stylesheets javascripts assets admin system api},
10
10
  reserved_site_handles: %w(sites my_account password sign_in sign_out),
11
11
  reserved_slugs: %w{stylesheets javascripts assets admin locomotive images api pages edit},
12
+ reserved_domains: [],
12
13
  locales: @@default_locales,
13
14
  site_locales: @@default_locales,
14
15
  cookie_key: '_locomotive_session',
@@ -18,6 +19,7 @@ module Locomotive
18
19
  default_locale: :en,
19
20
  mailer_sender: 'support@example.com',
20
21
  unsafe_token_authentication: false,
22
+ enable_registration: true,
21
23
  ui: {
22
24
  per_page: 10
23
25
  },
@@ -53,7 +53,7 @@ module Locomotive
53
53
  # if accounts but no site, redirect to the sign in page
54
54
  def handle_no_account_or_site(env, request)
55
55
  if Locomotive::Account.count == 0
56
- redirect_to(sign_up_path)
56
+ redirect_to((Locomotive.config.enable_registration ? sign_up_path : sign_in_path))
57
57
  elsif default_host?(request)
58
58
  redirect_to(sign_in_path)
59
59
  else
@@ -1,4 +1,3 @@
1
- require 'locomotive/mongoid/presenter'
2
1
  require 'locomotive/mongoid/liquid'
3
2
  require 'locomotive/mongoid/document'
4
3
  require 'locomotive/mongoid/patches'
@@ -1,13 +1,13 @@
1
1
  module Locomotive
2
2
  module Regexps
3
3
 
4
- # SUBDOMAIN = /^[a-z][a-z0-9_-]*[a-z0-9]{1}$/
5
-
6
4
  HANDLE = /^[a-z][a-z0-9_-]*[a-z0-9]{1}$/
7
5
 
8
6
  DOMAIN = /^(([a-z\d])([a-z\d-]){0,61}([a-z\d]))(\.([a-z\d])([a-z\d-]){0,61}([a-z\d]))*$/i
9
7
 
10
- URL = /((http|https|ftp):\/)?\/\S*/
8
+ URL = /\A((https?:\/\/)|(ftp:\/))\S+\Z/
9
+
10
+ URL_AND_MAILTO = /\A((https?:\/\/\S+)|(ftp:\/\S+)|(mailto:\S+)|\/\S*)\Z/
11
11
 
12
12
  end
13
13
  end
@@ -40,6 +40,7 @@ module Locomotive
40
40
  model_name = model_names.join('.')
41
41
 
42
42
  _key = [
43
+ Locomotive::VERSION,
43
44
  I18n.locale,
44
45
  template.instance_variable_get(:"@virtual_path"),
45
46
  namespace,
@@ -47,7 +47,7 @@ module Locomotive
47
47
  !env['steam.live_editing'] &&
48
48
  env['steam.site'].try(:cache_enabled) &&
49
49
  env['steam.page'].try(:cache_enabled) &&
50
- env['steam.page'].try(:redirect_url).blank?
50
+ is_redirect_url?(env['steam.page'], env['steam.locale'])
51
51
  end
52
52
 
53
53
  def cache_key(env)
@@ -56,6 +56,11 @@ module Locomotive
56
56
  Digest::MD5.hexdigest(key)
57
57
  end
58
58
 
59
+ def is_redirect_url?(page, locale)
60
+ return false if page.nil?
61
+ (page.try(:redirect_url) || {})[locale].blank?
62
+ end
63
+
59
64
  end
60
65
 
61
66
  end
@@ -13,13 +13,35 @@ module Locomotive
13
13
  def call(env)
14
14
  status, headers, response = @app.call(env)
15
15
 
16
- site, page, locale, live_editing = env['steam.site'], env['steam.page'], env['steam.locale'].to_s, env['steam.live_editing']
16
+ site, mounted_on, page, locale, live_editing = env['steam.site'], env['steam.mounted_on'], env['steam.page'], env['steam.locale'].to_s, env['steam.live_editing']
17
17
 
18
18
  if editable?(page, response, live_editing)
19
19
  html = %(
20
20
  <meta name="locomotive-locale" content="#{locale}" />
21
21
  <meta name="locomotive-editable-elements-path" content="#{editable_elements_path(site, page, locale, env)}" />
22
22
  <meta name="locomotive-page-id" content="#{page._id}" />
23
+ <meta name="locomotive-mounted-on" content="#{mounted_on}" />
24
+
25
+ <link href='https://fonts.googleapis.com/css?family=Noto+Sans' rel='stylesheet' type='text/css'>
26
+
27
+ <!-- [Locomotive] fix absolute links to inner pages in preview mode-->
28
+ <script>
29
+ window.document.addEventListener('click', function (event) {
30
+ var qs = document.querySelectorAll('a');
31
+ if (qs) {
32
+ var el = event.target, index = -1;
33
+ while (el && ((index = Array.prototype.indexOf.call(qs, el)) === -1)) {
34
+ el = el.parentElement;
35
+ }
36
+ if (index > -1) {
37
+ var url = el.getAttribute('href');
38
+ if (url[0] == '/' && url.indexOf('#{mounted_on}') == -1 ) {
39
+ el.setAttribute('href', '#{mounted_on}' + url);
40
+ }
41
+ }
42
+ }
43
+ });
44
+ </script>
23
45
  )
24
46
  response.first.gsub!('</head>', %(#{html}</head>))
25
47
  end
@@ -52,6 +52,6 @@ end
52
52
 
53
53
  Locomotive::Common.reset
54
54
  Locomotive::Common.configure do |config|
55
- config_file = Rails.root.join('log', 'steam.log')
55
+ config_file = ENV['LOCOMOTIVE_STEAM_LOG'] || Rails.root.join('log', 'steam.log')
56
56
  config.notifier = Locomotive::Common::Logger.setup(config_file.to_s)
57
57
  end
@@ -2,5 +2,5 @@
2
2
  # MAJOR.MINOR.PATCH format.
3
3
  # 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0
4
4
  module Locomotive #:nodoc
5
- VERSION = '3.0.0'
5
+ VERSION = '3.0.1'
6
6
  end
@@ -57,4 +57,8 @@ Locomotive.configure do |config|
57
57
  #
58
58
  # Note: by default, rack/cache is disabled in the Heroku platform
59
59
 
60
+ # Indicate whether you want to allow users to register with the site. If set
61
+ # to false the registration page will not be shown. (Default: true)
62
+ # config.enable_registration = true
63
+
60
64
  end
@@ -131,4 +131,5 @@ test:
131
131
  hosts:
132
132
  - localhost:27017
133
133
  options:
134
+ truncate_logs: false
134
135
  max_pool_size: 1
@@ -23,6 +23,31 @@ describe Locomotive::Concerns::Page::Redirect do
23
23
  expect(page.errors[:redirect_type]).to eq(["can't be blank"])
24
24
  end
25
25
 
26
+ it 'requires valid URLs' do
27
+ page.redirect_url = 'http:/foo.fr'
28
+ page.valid?
29
+ expect(page.errors[:redirect_url]).to eq(['is invalid'])
30
+
31
+ page.redirect_url = 'httpss://foo.fr'
32
+ page.valid?
33
+ expect(page.errors[:redirect_url]).to eq(['is invalid'])
34
+ end
35
+
36
+ it 'allows absolute urls' do
37
+ page.redirect_url = '/'
38
+ page.valid?
39
+ expect(page.errors[:redirect_url]).to be_blank
40
+ page.redirect_url = '/foo/bar'
41
+ page.valid?
42
+ expect(page.errors[:redirect_url]).to be_blank
43
+ end
44
+
45
+ it 'also allows mailto as a valid URL' do
46
+ page.redirect_url = 'mailto:foo@foo.fr'
47
+ page.valid?
48
+ expect(page.errors[:redirect_url]).to be_blank
49
+ end
50
+
26
51
  end
27
52
 
28
53
  end
@@ -14,6 +14,35 @@ describe Locomotive::Concerns::Site::AccessPoints do
14
14
  end
15
15
  end
16
16
 
17
+ describe '#valid?' do
18
+
19
+ subject { site.valid? }
20
+
21
+ it { is_expected.to eq true }
22
+
23
+ describe 'forbidden domains defined' do
24
+
25
+ before { allow(Locomotive.config).to receive(:reserved_domains).and_return(['www.locomotiveapp.com', /.+\.acme\.org/]) }
26
+
27
+ let(:domains) { ['example.fr', 'acme.org'] }
28
+
29
+ it { is_expected.to eq true }
30
+
31
+ context 'setting a forbidden domain name' do
32
+
33
+ let(:domains) { ['example.fr', 'www.locomotiveapp.com', 'staging.acme.org'] }
34
+
35
+ it 'adds errors for each invalid domain' do
36
+ is_expected.to eq false
37
+ expect(site.errors['domains']).to eq(["www.locomotiveapp.com is already taken", "staging.acme.org is already taken"])
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
17
46
  describe 'domain sync' do
18
47
 
19
48
  let!(:listener) { DomainEventListener.new }
@@ -47,7 +47,17 @@ describe Locomotive::Middlewares::Site do
47
47
  subject { middleware.call(env_for(url)) }
48
48
 
49
49
  it { expect(subject.first).to eq 301 }
50
- it { expect(subject[1]['Location']).to eq '/locomotive/sign_up' }
50
+
51
+ context 'default config' do
52
+ it { expect(subject[1]['Location']).to eq '/locomotive/sign_up' }
53
+ end
54
+
55
+ context 'config enable_registration set to false' do
56
+
57
+ before { allow(Locomotive.config).to receive(:enable_registration).and_return(false) }
58
+
59
+ it { expect(subject[1]['Location']).to eq '/locomotive/sign_in' }
60
+ end
51
61
 
52
62
  end
53
63
 
@@ -39,7 +39,7 @@ describe Locomotive::Steam::Middlewares::Cache do
39
39
 
40
40
  subject { middleware.send(:cache_key, steam_env) }
41
41
 
42
- it { expect(subject).to eq 'af996b364aaafa8c8f5bd89d7af70a07' }
42
+ it { expect(subject).to eq '5d728f9f71240d744cd635d03afc5969' }
43
43
 
44
44
  end
45
45
 
@@ -74,7 +74,8 @@ describe Locomotive::Steam::Middlewares::Cache do
74
74
 
75
75
  context 'page is a redirection' do
76
76
 
77
- let(:page) { instance_double('CachedPage', _id: '0042', cache_enabled: page_cache, redirect_url: 'http://locomotive.works') }
77
+ let(:i18n_field) { instance_double('I18nField', :[] => { 'en' => 'http://locomotive.works' }) }
78
+ let(:page) { instance_double('CachedPage', _id: '0042', cache_enabled: page_cache, redirect_url: i18n_field) }
78
79
  it { expect(subject).to eq false }
79
80
 
80
81
  end