alchemy_cms 3.1.0.rc1 → 3.1.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -10
  3. data/.teatro.yml +7 -0
  4. data/Gemfile +13 -13
  5. data/README.md +20 -3
  6. data/app/assets/javascripts/alchemy/alchemy.translations.js.coffee +3 -3
  7. data/app/assets/javascripts/alchemy/alchemy.uploader.js.coffee +5 -0
  8. data/app/controllers/alchemy/admin/essence_files_controller.rb +23 -3
  9. data/app/controllers/alchemy/admin/essence_pictures_controller.rb +7 -2
  10. data/app/controllers/alchemy/admin/pictures_controller.rb +1 -4
  11. data/app/controllers/alchemy/base_controller.rb +3 -1
  12. data/app/controllers/alchemy/pages_controller.rb +3 -1
  13. data/app/models/alchemy/content.rb +0 -3
  14. data/app/models/alchemy/element.rb +1 -2
  15. data/app/models/alchemy/page/page_scopes.rb +3 -1
  16. data/app/models/alchemy/page/page_users.rb +10 -3
  17. data/app/models/alchemy/picture.rb +29 -6
  18. data/app/models/alchemy/picture/transformations.rb +14 -7
  19. data/app/views/alchemy/_menubar.html.erb +1 -1
  20. data/app/views/alchemy/admin/leave.html.erb +1 -1
  21. data/app/views/alchemy/essences/_essence_boolean_editor.html.erb +2 -1
  22. data/config/initializers/dragonfly.rb +0 -2
  23. data/lib/alchemy/engine.rb +0 -1
  24. data/lib/alchemy/locale.rb +15 -13
  25. data/lib/alchemy/upgrader.rb +1 -0
  26. data/lib/alchemy/upgrader/three_point_zero.rb +27 -9
  27. data/lib/alchemy/version.rb +1 -1
  28. data/lib/tasks/alchemy/tidy.rake +34 -16
  29. data/spec/controllers/admin/essence_files_controller_spec.rb +13 -2
  30. data/spec/controllers/admin/essence_pictures_controller_spec.rb +8 -0
  31. data/spec/controllers/pages_controller_spec.rb +42 -0
  32. data/spec/dummy/app/controllers/application_controller.rb +5 -1
  33. data/spec/dummy/app/models/dummy_user.rb +4 -0
  34. data/spec/dummy/bin/bundle +0 -0
  35. data/spec/dummy/bin/rails +0 -0
  36. data/spec/dummy/bin/rake +0 -0
  37. data/spec/dummy/config/environments/production.rb +1 -1
  38. data/spec/dummy/db/seeds.rb +1 -0
  39. data/spec/features/translation_integration_spec.rb +14 -11
  40. data/spec/models/page_spec.rb +143 -52
  41. data/spec/spec_helper.rb +0 -3
  42. data/spec/support/transformation_examples.rb +7 -0
  43. data/spec/views/essences/essence_boolean_editor_spec.rb +1 -0
  44. data/vendor/assets/javascripts/fileupload/jquery.fileupload-process.js +6 -3
  45. data/vendor/assets/javascripts/fileupload/jquery.fileupload-validate.js +5 -3
  46. data/vendor/assets/javascripts/fileupload/jquery.fileupload.js +97 -46
  47. data/vendor/assets/javascripts/fileupload/jquery.iframe-transport.js +11 -4
  48. metadata +6 -4
  49. data/lib/extensions/action_view.rb +0 -17
@@ -5,7 +5,7 @@
5
5
  <li><%= link_to _t(:edit_page), alchemy.edit_admin_page_path(@page) %></li>
6
6
  <li>
7
7
  <%= form_tag Alchemy.logout_path, method: 'delete' do %>
8
- <%= button _t(:logout) %>
8
+ <%= button_tag _t(:logout) %>
9
9
  <% end %>
10
10
  </li>
11
11
  </ul>
@@ -7,5 +7,5 @@
7
7
  </p>
8
8
  <%= form_tag Alchemy.logout_path, method: 'delete', class: 'buttons' do %>
9
9
  <label><%= _t('or to completely') %></label>
10
- <%= button _t(:logout), autofocus: true %>
10
+ <%= button_tag _t(:logout), autofocus: true %>
11
11
  <% end %>
@@ -9,7 +9,8 @@
9
9
  style: local_assigns.fetch(:html_options, {})[:style] %>
10
10
  <label for="<%= content.form_field_id %>" style="display: inline">
11
11
  <%= render_content_name(content) %>
12
- <%= delete_content_link(content) %>
13
12
  </label>
13
+ <%= delete_content_link(content) %>
14
+ <%= render_hint_for(content) %>
14
15
  </div>
15
16
  <% end %>
@@ -6,8 +6,6 @@ Dragonfly.app(:alchemy_pictures).configure do
6
6
  datastore :file,
7
7
  root_path: Rails.root.join('uploads/pictures').to_s,
8
8
  store_meta: false
9
- url_format '/pictures/:job/:basename.:format'
10
- url_path_prefix Alchemy::MountPoint.get
11
9
  end
12
10
 
13
11
  # Attachments
@@ -45,7 +45,6 @@ require_relative './touching'
45
45
 
46
46
  # Require hacks
47
47
  require_relative './kaminari/scoped_pagination_url_helper'
48
- require_relative '../extensions/action_view'
49
48
 
50
49
  # Middleware
51
50
  require_relative './middleware/rescue_old_cookies'
@@ -10,20 +10,17 @@ module Alchemy
10
10
 
11
11
  # Sets Alchemy's GUI translation.
12
12
  #
13
- # * If one passed a locale via +params[:locale]+ it uses this.
14
- # * Or it tries to get users preffered language.
15
- # * If not found it guesses the language from the browser locale.
16
- # * If that also fails it takes the default.
13
+ # Uses the most preferred locale or falls back to the default locale if none of the preferred is available.
17
14
  #
18
15
  # It respects the default translation from your +config/application.rb+ +default_locale+ config option.
19
16
  #
20
17
  def set_translation
21
18
  if locale_change_needed?
22
- ::I18n.locale = session[:alchemy_locale] = locale_from_params ||
23
- locale_from_user || locale_from_browser || ::I18n.default_locale
19
+ locale = available_locale || ::I18n.default_locale
24
20
  else
25
- ::I18n.locale = session[:alchemy_locale]
21
+ locale = session[:alchemy_locale]
26
22
  end
23
+ ::I18n.locale = session[:alchemy_locale] = locale
27
24
  end
28
25
 
29
26
  # Checks if we need to change to locale or not.
@@ -31,12 +28,17 @@ module Alchemy
31
28
  params[:locale].present? || session[:alchemy_locale].blank?
32
29
  end
33
30
 
34
- # Try to get the locale from +params[:locale]+.
35
- def locale_from_params
36
- return if params[:locale].blank?
37
- if ::I18n.available_locales.include?(params[:locale].to_sym)
38
- params[:locale]
39
- end
31
+ # Returns either the most preferred locale that is within the list of available locales or nil
32
+ #
33
+ # The availability of the locales is checked in the exact order of either
34
+ #
35
+ # * the passed parameter: +params[:locale]+
36
+ # * the user's locale
37
+ # * the locale of the browser
38
+ #
39
+ def available_locale
40
+ locales = [params[:locale], locale_from_user, locale_from_browser].compact
41
+ locales.detect { |locale| ::I18n.available_locales.include?(locale.to_sym) }
40
42
  end
41
43
 
42
44
  # Try to get the locale from user settings.
@@ -5,6 +5,7 @@ module Alchemy
5
5
 
6
6
  Dir["#{File.dirname(__FILE__)}/upgrader/*.rb"].each { |f| require f }
7
7
 
8
+ extend Alchemy::Upgrader::ThreePointOne
8
9
  extend Alchemy::Upgrader::ThreePointZero
9
10
 
10
11
  class << self
@@ -3,16 +3,20 @@ module Alchemy
3
3
  private
4
4
 
5
5
  def rename_registered_role_ro_member
6
- desc 'Rename the `registered` user role to `member`'
7
- registered_users = Alchemy.user_class.where("alchemy_roles LIKE '%registered%'")
8
- if registered_users.any?
9
- registered_users.each do |user|
10
- roles = user.read_attribute(:alchemy_roles).sub(/registered/, 'member')
11
- user.update_column(:alchemy_roles, roles)
12
- log "Renamed #{user.inspect} role to `member`"
6
+ if Alchemy.user_class.column_names.include?('alchemy_roles')
7
+ desc 'Rename the `registered` user role to `member`'
8
+ registered_users = Alchemy.user_class.where("alchemy_roles LIKE '%registered%'")
9
+ if registered_users.any?
10
+ registered_users.each do |user|
11
+ roles = user.read_attribute(:alchemy_roles).sub(/registered/, 'member')
12
+ user.update_column(:alchemy_roles, roles)
13
+ log "Renamed #{user.inspect} role to `member`"
14
+ end
15
+ else
16
+ log 'No users with `registered` role found.', :skip
13
17
  end
14
18
  else
15
- log 'No users with `registered` role found.', :skip
19
+ log 'No users with `alchemy_roles` database column found.', :skip
16
20
  end
17
21
  end
18
22
 
@@ -29,7 +33,7 @@ module Alchemy
29
33
  end
30
34
  end
31
35
 
32
- def alchemy_3_todos
36
+ def alchemy_3_0_todos
33
37
  notice = <<-NOTE
34
38
 
35
39
  Alchemy User Class Removed
@@ -67,6 +71,20 @@ also read the official TinyMCE documentation in how to upgrade.
67
71
  Alchemy default TinyMCE config: https://github.com/magiclabs/alchemy_cms/blob/master/lib/alchemy/tinymce.rb#L5-L19
68
72
  Offical TinyMCE documentation: http://www.tinymce.com/wiki.php/Configuration
69
73
 
74
+
75
+ Essence Validation Syntax changed
76
+ ---------------------------------
77
+
78
+ The API of the format validations for essences has changed.
79
+ You can now define individual format matchers in the config.yml.
80
+
81
+ * `format_as` and `format_with` options has been removed and renamed to simply `format`
82
+
83
+ Pleae have a look at this commit:
84
+ https://github.com/AlchemyCMS/alchemy_cms/commit/44866dbebaed00ffa3b77201f93a04616001b955
85
+
86
+ for a detailed explanation.
87
+
70
88
  NOTE
71
89
  todo notice, 'Alchemy v3.0 changes'
72
90
  end
@@ -1,5 +1,5 @@
1
1
  module Alchemy
2
- VERSION = "3.1.0.rc1"
2
+ VERSION = "3.1.0.rc2"
3
3
 
4
4
  def self.version
5
5
  VERSION
@@ -5,16 +5,21 @@ namespace :alchemy do
5
5
  task :up do
6
6
  Rake::Task['alchemy:tidy:cells'].invoke
7
7
  Rake::Task['alchemy:tidy:element_positions'].invoke
8
+ Rake::Task['alchemy:tidy:content_positions'].invoke
8
9
  end
9
10
 
10
11
  desc "Creates missing cells for pages."
11
12
  task :cells => :environment do
12
- cells = Alchemy::Cell.definitions
13
- page_layouts = Alchemy::PageLayout.all
14
- if cells && page_layouts
15
- Alchemy::Tidy.create_missing_cells(page_layouts, cells)
13
+ if !File.exist? Rails.root.join('config/alchemy/cells.yml')
14
+ puts "No page cell definitions found."
16
15
  else
17
- puts "No page layouts or cell definitions found."
16
+ cells = Alchemy::Cell.definitions
17
+ page_layouts = Alchemy::PageLayout.all
18
+ if cells && page_layouts
19
+ Alchemy::Tidy.create_missing_cells(page_layouts, cells)
20
+ else
21
+ puts "No page layouts or cell definitions found."
22
+ end
18
23
  end
19
24
  end
20
25
 
@@ -23,6 +28,10 @@ namespace :alchemy do
23
28
  Alchemy::Tidy.update_element_positions
24
29
  end
25
30
 
31
+ desc "Fixes content positions."
32
+ task :content_positions => [:environment] do
33
+ Alchemy::Tidy.update_content_positions
34
+ end
26
35
  end
27
36
  end
28
37
 
@@ -31,7 +40,6 @@ module Alchemy
31
40
  extend Shell
32
41
 
33
42
  def self.create_missing_cells(page_layouts, cells)
34
- desc "Create missing cells"
35
43
  page_layouts.each do |layout|
36
44
  next if layout['cells'].blank?
37
45
  cells_for_layout = cells.select { |cell| layout['cells'].include? cell['name'] }
@@ -51,8 +59,10 @@ module Alchemy
51
59
  end
52
60
 
53
61
  def self.update_element_positions
54
- desc "Update element positions"
55
62
  Alchemy::Page.all.each do |page|
63
+ if page.elements.any?
64
+ puts "\n## Updating element positions of page `#{page.name}`"
65
+ end
56
66
  page.elements.group_by(&:cell_id).each do |cell_id, elements|
57
67
  elements.each_with_index do |element, idx|
58
68
  position = idx + 1
@@ -60,23 +70,31 @@ module Alchemy
60
70
  log "Updating position for element ##{element.id} to #{position}"
61
71
  element.update_column(:position, position)
62
72
  else
63
- log "Position for element ##{element.id} is already correct", :skip
73
+ log "Position for element ##{element.id} is already correct (#{position})", :skip
64
74
  end
65
75
  end
66
76
  end
67
77
  end
68
78
  end
69
79
 
70
- # TODO: implement remove_orphan_cells
71
- def self.remove_orphan_cells(page_layouts, cells)
72
- puts "== Remove cell orphans"
73
- Alchemy::Cell.all.each do |cell|
74
- if cells.detect { |cell| cell['name'] == cell.name }.nil?
75
- # move elements to page or into another cell of page
76
- # remove cell from database
80
+ def self.update_content_positions
81
+ Alchemy::Element.all.each do |element|
82
+ if element.contents.any?
83
+ puts "\n## Updating content positions of element `#{element.name}`"
84
+ end
85
+ element.contents.group_by(&:essence_type).each do |essence_type, contents|
86
+ puts "-> Contents of type `#{essence_type}`"
87
+ contents.each_with_index do |content, idx|
88
+ position = idx + 1
89
+ if content.position != position
90
+ log "Updating position for content ##{content.id} to #{position}"
91
+ content.update_column(:position, position)
92
+ else
93
+ log "Position for content ##{content.id} is already correct (#{position})", :skip
94
+ end
95
+ end
77
96
  end
78
97
  end
79
98
  end
80
-
81
99
  end
82
100
  end
@@ -29,17 +29,22 @@ module Alchemy
29
29
  end
30
30
 
31
31
  describe '#update' do
32
+ let(:essence_file) { FactoryGirl.create(:essence_file) }
33
+
32
34
  before do
33
35
  expect(EssenceFile).to receive(:find).and_return(essence_file)
34
36
  end
35
37
 
36
38
  it "should update the attributes of essence_file" do
37
- expect(essence_file).to receive(:update).and_return(true)
38
- xhr :put, :update, id: essence_file.id
39
+ xhr :put, :update, id: essence_file.id, essence_file: {title: 'new title', css_class: 'left'}
40
+ expect(essence_file.title).to eq 'new title'
41
+ expect(essence_file.css_class).to eq 'left'
39
42
  end
40
43
  end
41
44
 
42
45
  describe '#assign' do
46
+ let(:content) { create(:content) }
47
+
43
48
  before do
44
49
  expect(Content).to receive(:find_by).and_return(content)
45
50
  expect(Attachment).to receive(:find_by).and_return(attachment)
@@ -55,6 +60,12 @@ module Alchemy
55
60
  expect(content.essence).to receive(:attachment=).with(attachment)
56
61
  xhr :put, :assign, content_id: content.id, attachment_id: attachment.id
57
62
  end
63
+
64
+ it "updates the @content.updated_at column" do
65
+ expect {
66
+ xhr :put, :assign, content_id: content.id, attachment_id: attachment.id
67
+ }.to change(content, :updated_at)
68
+ end
58
69
  end
59
70
  end
60
71
  end
@@ -179,6 +179,8 @@ module Alchemy
179
179
  end
180
180
 
181
181
  describe '#assign' do
182
+ let(:content) { create(:content) }
183
+
182
184
  before do
183
185
  expect(Content).to receive(:find).and_return(content)
184
186
  expect(content).to receive(:essence).at_least(:once).and_return(essence)
@@ -189,6 +191,12 @@ module Alchemy
189
191
  xhr :put, :assign, content_id: '1', picture_id: '1'
190
192
  expect(assigns(:content).essence.picture).to eq(picture)
191
193
  end
194
+
195
+ it "updates the content timestamp" do
196
+ expect {
197
+ xhr :put, :assign, content_id: '1', picture_id: '1'
198
+ }.to change(content, :updated_at)
199
+ end
192
200
  end
193
201
  end
194
202
  end
@@ -229,5 +229,47 @@ module Alchemy
229
229
  end
230
230
  end
231
231
  end
232
+
233
+ describe '#cache_page?' do
234
+ subject { controller.send(:cache_page?) }
235
+
236
+ before do
237
+ Rails.application.config.action_controller.perform_caching = true
238
+ controller.instance_variable_set('@page', page)
239
+ end
240
+
241
+ it 'returns true when everthing is alright' do
242
+ expect(subject).to be true
243
+ end
244
+
245
+ it 'returns false when the Rails app does not perform caching' do
246
+ Rails.application.config.action_controller.perform_caching = false
247
+ expect(subject).to be false
248
+ end
249
+
250
+ it 'returns false when there is no page' do
251
+ controller.instance_variable_set('@page', nil)
252
+ expect(subject).to be false
253
+ end
254
+
255
+ it 'returns false when caching is deactivated in the Alchemy config' do
256
+ allow(Alchemy::Config).to receive(:get).with(:cache_pages).and_return(false)
257
+ expect(subject).to be false
258
+ end
259
+
260
+ it 'returns false when the page layout is set to cache = false' do
261
+ page_layout = PageLayout.get('news')
262
+ page_layout['cache'] = false
263
+ allow(PageLayout).to receive(:get).with('news').and_return(page_layout)
264
+ expect(subject).to be false
265
+ end
266
+
267
+ it 'returns false when the page layout is set to searchresults = true' do
268
+ page_layout = PageLayout.get('news')
269
+ page_layout['searchresults'] = true
270
+ allow(PageLayout).to receive(:get).with('news').and_return(page_layout)
271
+ expect(subject).to be false
272
+ end
273
+ end
232
274
  end
233
275
  end
@@ -6,6 +6,10 @@ class ApplicationController < ActionController::Base
6
6
  private
7
7
 
8
8
  def current_user
9
- nil
9
+ if Rails.env.test?
10
+ nil
11
+ else
12
+ DummyUser.new(email: "dummy@alchemy.com")
13
+ end
10
14
  end
11
15
  end
@@ -4,4 +4,8 @@ class DummyUser < ActiveRecord::Base
4
4
  def self.logged_in
5
5
  []
6
6
  end
7
+
8
+ def alchemy_roles
9
+ %w(admin)
10
+ end
7
11
  end
File without changes
File without changes
File without changes
@@ -27,7 +27,7 @@ Dummy::Application.configure do
27
27
  # config.assets.css_compressor = :sass
28
28
 
29
29
  # Do not fallback to assets pipeline if a precompiled asset is missed.
30
- config.assets.compile = false
30
+ config.assets.compile = true
31
31
 
32
32
  # Generate digests for assets URLs.
33
33
  config.assets.digest = true
@@ -0,0 +1 @@
1
+ Alchemy::Seeder.seed!
@@ -2,17 +2,19 @@ require 'spec_helper'
2
2
 
3
3
  describe "Translation integration" do
4
4
  context "in admin backend" do
5
- before { authorize_as_admin(mock_model('DummyUser', alchemy_roles: %w(admin), language: 'de')) }
5
+ let(:dummy_user) { mock_model('DummyUser', alchemy_roles: %w(admin), language: 'de') }
6
+
7
+ before { authorize_as_admin(dummy_user) }
6
8
 
7
9
  it "should be possible to set the locale of the admin backend via params" do
8
- visit admin_dashboard_path(locale: 'de')
9
- expect(page).to have_content('Willkommen')
10
+ visit admin_dashboard_path(locale: 'nl')
11
+ expect(page).to have_content('Welkom')
10
12
  end
11
13
 
12
14
  it "should store the current locale in the session" do
13
- visit admin_dashboard_path(locale: 'de')
15
+ visit admin_dashboard_path(locale: 'nl')
14
16
  visit admin_dashboard_path
15
- expect(page).to have_content('Willkommen')
17
+ expect(page).to have_content('Welkom')
16
18
  end
17
19
 
18
20
  it "should be possible to change the current locale in the session" do
@@ -34,14 +36,15 @@ describe "Translation integration" do
34
36
  visit admin_dashboard_path
35
37
  expect(page).to have_content('Willkommen')
36
38
  end
37
- end
38
39
 
39
- context "with translated header" do
40
- before { Capybara.current_driver = :rack_test_translated_header }
40
+ context "if user has no preferred locale" do
41
+ let(:dummy_user) { mock_model('DummyUser', alchemy_roles: %w(admin), language: nil) }
41
42
 
42
- it "should use the browsers language setting if no other parameter is given" do
43
- visit admin_dashboard_path
44
- expect(page).to have_content('Willkommen')
43
+ it "should use the browsers language setting" do
44
+ page.driver.header 'ACCEPT-LANGUAGE', 'es-ES'
45
+ visit admin_dashboard_path
46
+ expect(page).to have_content('Bienvenido')
47
+ end
45
48
  end
46
49
  end
47
50
  end