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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 90a343fa98a444500a06cfbaa172e6bb8c6b4856
4
- data.tar.gz: fc1c96763f1a10a0938f54057b5bdc04f81dc002
3
+ metadata.gz: 64b4c80e471321ff237ae2fa6232841e2769f1fc
4
+ data.tar.gz: c66e6fbc68e16aa584ac6801d32821a3e04267f1
5
5
  SHA512:
6
- metadata.gz: 910b2641a2a94dfd31289b4f3d41f13e5b02f2ae1e543a1f4dc30627c9451500c9e34510058be064fa53de2c576b9bd770ed07f479bc69c0323b479e97c5fa92
7
- data.tar.gz: f05aac4f401eb397193dbb5a07a22e279fdb2cae66165b8ca7033e0f2415074f42d0d91e12588c2e44d8f7b2108fa25e1f3fbc62d7e7ce696cff23097778688c
6
+ metadata.gz: 3e43c4db264c179ebc193d8ace01227b9e94570b82c8c6f4c572e4cb1e5cfcd66995fa99a7326d57ac65f144da95f47c8aa28b2c2358dcf79afc4ea844672464
7
+ data.tar.gz: 326af8d144fdab241db4c6e41c8f981364b4ab5552c86132ba05f61aafe25ac06f635742c9f1f610e0c2f0d2f6ff026b833e69aaf32c1268b0f2a2860cf7f9ae
data/.gitignore CHANGED
@@ -6,22 +6,16 @@ doc/
6
6
  rdoc/
7
7
  Gemfile.lock
8
8
  pkg
9
- /spec/dummy/log/development.log
10
- /spec/dummy/log/test.log
11
- /spec/dummy/db/test.sqlite3
12
- /spec/dummy/db/development.sqlite3
13
9
  tmp
14
- spec/dummy/index/
15
10
  log
16
- spec/dummy/uploads/
17
11
  .sass-cache
18
- spec/dummy/db/test.sqlite3-journal
19
- spec/dummy/db/seeds.rb
20
- .rvmrc
12
+ spec/dummy/uploads/
13
+ spec/dummy/db/*.sqlite3*
14
+ spec/dummy/public/assets
21
15
  spec/dummy/config/locales/**/*
16
+ .rvmrc
22
17
  /coverage/
23
18
  *.gem
24
- /.ruby-version
25
19
  /index/
26
20
  /.bundle/
27
21
  .rbenv-version
@@ -0,0 +1,7 @@
1
+ project:
2
+ after:
3
+ - apt-get -y install imagemagick
4
+ stage:
5
+ before: cd spec/dummy
6
+ database: bin/rake db:setup RAILS_ENV=production
7
+ run: bin/rails server -e production
data/Gemfile CHANGED
@@ -6,20 +6,16 @@ if ENV['RAILS_VERSION']
6
6
  gem 'rails', "~> #{ENV['RAILS_VERSION']}"
7
7
  end
8
8
 
9
- # Code coverage plattform
10
- gem 'coveralls', require: false
11
-
12
- group :test do
13
- gem 'sqlite3' if ENV['DB'].nil? || ENV['DB'] == 'sqlite'
14
- gem 'mysql2' if ENV['DB'] == 'mysql'
15
- gem 'pg' if ENV['DB'] == 'postgresql'
16
- unless ENV['CI']
17
- gem 'launchy'
18
- end
19
- end
9
+ gem 'sqlite3' if ENV['DB'].nil? || ENV['DB'] == 'sqlite'
10
+ gem 'mysql2' if ENV['DB'] == 'mysql'
11
+ gem 'pg' if ENV['DB'] == 'postgresql'
20
12
 
21
13
  group :development, :test do
14
+ gem 'jasmine-rails', github: 'searls/jasmine-rails'
15
+ gem 'jasmine-jquery-rails', github: 'travisjeffery/jasmine-jquery-rails'
16
+ gem 'coveralls', require: false
22
17
  unless ENV['CI']
18
+ gem 'launchy'
23
19
  gem 'annotate'
24
20
  gem 'bumpy'
25
21
  gem 'yard'
@@ -28,6 +24,10 @@ group :development, :test do
28
24
  gem 'spring'
29
25
  gem 'spring-commands-rspec'
30
26
  end
31
- gem 'jasmine-rails', github: 'searls/jasmine-rails'
32
- gem 'jasmine-jquery-rails', github: 'travisjeffery/jasmine-jquery-rails'
27
+ end
28
+
29
+ # We need this if we want to start the dummy app in production, ie on Teatro.io
30
+ group :production do
31
+ gem 'uglifier', '>= 1.0.3'
32
+ gem 'therubyracer'
33
33
  end
data/README.md CHANGED
@@ -261,11 +261,18 @@ Please take a look into Alchemys [Capistrano receipt](https://github.com/Alchemy
261
261
 
262
262
  If you want to contribute to Alchemy ([and we encourage you to do so](https://github.com/AlchemyCMS/alchemy_cms/blob/master/CONTRIBUTING.md)) we have a strong test suite that helps you to not break anything.
263
263
 
264
+ ### Preparation
265
+
266
+ First of all you need to clone your fork to your local development machine. Then you need to install the dependencies with bundler.
267
+
268
+ ```shell
269
+ $ bundle install
270
+ ```
271
+
264
272
  To prepare the tests of your Alchemy fork please make sure to run the preparation task:
265
273
 
266
274
  ```shell
267
- # ~/your/local/alchemy_cms
268
- $ bin/rake alchemy:spec:prepare
275
+ $ bundle exec rake alchemy:spec:prepare
269
276
  ```
270
277
 
271
278
  to set up the database for testing.
@@ -276,7 +283,7 @@ to set up the database for testing.
276
283
  $ bundle exec rspec
277
284
  ```
278
285
 
279
- **Alternatively** you can just run:
286
+ **Alternatively** you can just run*:
280
287
 
281
288
  ```shell
282
289
  $ bundle exec rake
@@ -284,6 +291,16 @@ $ bundle exec rake
284
291
 
285
292
  *) This default task executes the database preparations and runs all defined test cases.
286
293
 
294
+ ### Start the dummy app
295
+
296
+ You can even start the dummy app and use it to manually test your changes with:
297
+
298
+ ```shell
299
+ $ cd spec/dummy
300
+ $ bin/rake db:setup
301
+ $ bin/rails s
302
+ ```
303
+
287
304
  **A note about RSpec version:**
288
305
 
289
306
  Alchemy specs are written **in RSpec 3**. Please **do not use deprecated RSpec 2.x syntax**. Thanks
@@ -22,8 +22,8 @@ Alchemy.translations =
22
22
  'File is too large': 'Datei ist zu groß.'
23
23
  'File is too small': 'Datei ist zu klein.'
24
24
  'File type not allowed': 'Dateityp nicht erlaubt.'
25
- 'Maximum number of files exceeded': 'Maximale Anzahl an Dateien erreicht.'
26
- 'Uploaded bytes exceed file size': 'Maximal erlaubte Dateigröße erreicht.'
25
+ 'Maximum number of files exceeded': 'Maximale Anzahl gleichzeitig erlaubter Datei-Uploads erreicht.'
26
+ 'Uploaded bytes exceed file size': 'Maximale Größe der erlaubten Dateigröße erreicht.'
27
27
 
28
28
  # English
29
29
  en:
@@ -109,7 +109,7 @@ Alchemy.translations =
109
109
  'File type not allowed': 'Этот тип файла не разрешен'
110
110
  'Maximum number of files exceeded': 'Исчерпано максимальное количество файлов.'
111
111
  'Uploaded bytes exceed file size': 'Превышен максимальный размер файла'
112
-
112
+
113
113
  # Spanish
114
114
  es:
115
115
  allowed_chars: 'de %{count} caracteres'
@@ -25,6 +25,7 @@ Alchemy.Uploader = (settings) ->
25
25
  $("#fileupload").fileupload
26
26
  dropZone: '#dropbox'
27
27
  dataType: 'json'
28
+ filesContainer: $('#uploadProgressContainer')
28
29
  acceptFileTypes: new RegExp("(.|/)(#{file_types})", "i")
29
30
  maxNumberOfFiles: settings.file_upload_limit
30
31
  maxFileSize: settings.file_size_limit * 1000000
@@ -32,6 +33,10 @@ Alchemy.Uploader = (settings) ->
32
33
  form_data = form.serializeArray()
33
34
  $.merge(form_data, settings.post_params)
34
35
  form_data
36
+ getNumberOfFiles: ->
37
+ @filesContainer
38
+ .children()
39
+ .not('.progressBarInProgress').length - 1
35
40
  add: (e, data) ->
36
41
  $this = $(this)
37
42
  data.context = new Alchemy.FileProgress(data.files[0])
@@ -3,24 +3,44 @@ module Alchemy
3
3
  class EssenceFilesController < Alchemy::Admin::BaseController
4
4
  authorize_resource class: Alchemy::EssenceFile
5
5
 
6
+ before_filter :load_essence_file, only: [:edit, :update]
7
+
6
8
  helper "Alchemy::Admin::Contents"
7
9
 
8
10
  def edit
9
- @essence_file = EssenceFile.find(params[:id])
10
11
  @content = @essence_file.content
11
12
  @options = options_from_params
12
13
  end
13
14
 
14
15
  def update
15
- @essence_file = EssenceFile.find(params[:id])
16
- @essence_file.update(params[:essence_file])
16
+ @essence_file.update(essence_file_params)
17
17
  end
18
18
 
19
+ # Assigns file, but does not saves it.
20
+ #
21
+ # When the user saves the element the content gets updated as well.
22
+ #
19
23
  def assign
20
24
  @content = Content.find_by(id: params[:content_id])
21
25
  @attachment = Attachment.find_by(id: params[:attachment_id])
22
26
  @content.essence.attachment = @attachment
23
27
  @options = options_from_params
28
+
29
+ # We need to update timestamp here because we don't save yet,
30
+ # but the cache needs to be get invalid.
31
+ # And we don't user @content.touch here, because that updates
32
+ # also the element and page timestamps what we don't want yet.
33
+ @content.update_column(:updated_at, Time.now)
34
+ end
35
+
36
+ private
37
+
38
+ def essence_file_params
39
+ params.require(:essence_file).permit(:title, :css_class)
40
+ end
41
+
42
+ def load_essence_file
43
+ @essence_file = EssenceFile.find(params[:id])
24
44
  end
25
45
  end
26
46
  end
@@ -36,15 +36,20 @@ module Alchemy
36
36
 
37
37
  # Assigns picture, but does not saves it.
38
38
  #
39
- # When the user press save on the element, it gets saved.
39
+ # When the user saves the element the content gets updated as well.
40
40
  #
41
41
  def assign
42
42
  @picture = Picture.find_by(id: params[:picture_id])
43
43
  @content.essence.picture = @picture
44
- @content.touch # We need to touch manually because its not saved yet.
45
44
  @element = @content.element
46
45
  @dragable = @options[:grouped]
47
46
  @options = @options.merge(dragable: @dragable)
47
+
48
+ # We need to update timestamp here because we don't save yet,
49
+ # but the cache needs to be get invalid.
50
+ # And we don't user @content.touch here, because that updates
51
+ # also the element and page timestamps what we don't want yet.
52
+ @content.update_column(:updated_at, Time.now)
48
53
  end
49
54
 
50
55
  def destroy
@@ -12,10 +12,7 @@ module Alchemy
12
12
 
13
13
  def index
14
14
  @size = params[:size].present? ? params[:size] : 'medium'
15
- @pictures = Picture.all
16
- @pictures = @pictures.tagged_with(params[:tagged_with]) if params[:tagged_with].present?
17
- @pictures = @pictures.filtered_by(params[:filter]) if params[:filter]
18
- @pictures = @pictures.find_paginated(params, pictures_per_page_for_size(@size))
15
+ @pictures = Picture.find_paginated(params, pictures_per_page_for_size(@size))
19
16
  if in_overlay?
20
17
  archive_overlay
21
18
  end
@@ -96,11 +96,13 @@ module Alchemy
96
96
  protected
97
97
 
98
98
  def permission_denied(exception = nil)
99
- Rails.logger.debug <<-WARN
99
+ if exception
100
+ Rails.logger.debug <<-WARN
100
101
 
101
102
  /!\\ Failed to permit #{exception.action} on #{exception.subject.inspect} for:
102
103
  #{current_alchemy_user.inspect}
103
104
  WARN
105
+ end
104
106
  if current_alchemy_user
105
107
  handle_redirect_for_user
106
108
  else
@@ -184,7 +184,9 @@ module Alchemy
184
184
  # @returns Boolean
185
185
  #
186
186
  def cache_page?
187
- return false unless @page && Alchemy::Config.get(:cache_pages)
187
+ return false if @page.nil? ||
188
+ !Rails.application.config.action_controller.perform_caching ||
189
+ !Alchemy::Config.get(:cache_pages)
188
190
  page_layout = PageLayout.get(@page.page_layout)
189
191
  page_layout['cache'] != false && page_layout['searchresults'] != true
190
192
  end
@@ -37,9 +37,6 @@ module Alchemy
37
37
  "element_id = #{element_id || 'null'} AND essence_type = '#{essence_type}'"
38
38
  end
39
39
 
40
- # Validations
41
- validates :position, uniqueness: {scope: [:element_id, :essence_type]}
42
-
43
40
  # Essence scopes
44
41
  scope :essence_booleans, -> { where(essence_type: "Alchemy::EssenceBoolean") }
45
42
  scope :essence_dates, -> { where(essence_type: "Alchemy::EssenceDate") }
@@ -29,7 +29,7 @@ module Alchemy
29
29
  acts_as_taggable
30
30
 
31
31
  # All Elements inside a cell are a list. All Elements not in cell are in the cell_id.nil list.
32
- acts_as_list :scope => [:page_id, :cell_id]
32
+ acts_as_list scope: [:page_id, :cell_id]
33
33
  stampable stamper_class_name: Alchemy.user_class_name
34
34
 
35
35
  has_many :contents, -> { order(:position) }, dependent: :destroy
@@ -39,7 +39,6 @@ module Alchemy
39
39
  class_name: 'Alchemy::Page',
40
40
  join_table: 'alchemy_elements_alchemy_pages'
41
41
 
42
- validates_uniqueness_of :position, :scope => [:page_id, :cell_id], :if => lambda { |e| e.position != nil }
43
42
  validates_presence_of :name, :on => :create
44
43
  validates_format_of :name, :on => :create, :with => /\A[a-z0-9_-]+\z/
45
44
 
@@ -21,7 +21,9 @@ module Alchemy
21
21
  # All pages locked by given user
22
22
  #
23
23
  scope :all_locked_by, ->(user) {
24
- all_locked.where(locked_by: user.id)
24
+ if user.class.respond_to? :primary_key
25
+ all_locked.where(locked_by: user.send(user.class.primary_key))
26
+ end
25
27
  }
26
28
 
27
29
  # All not locked pages
@@ -5,19 +5,19 @@ module Alchemy
5
5
  # Returns the creator of this page.
6
6
  #
7
7
  def creator
8
- Alchemy.user_class.try(:find_by, {id: creator_id})
8
+ get_page_user(creator_id)
9
9
  end
10
10
 
11
11
  # Returns the last updater of this page.
12
12
  #
13
13
  def updater
14
- Alchemy.user_class.try(:find_by, {id: updater_id})
14
+ get_page_user(updater_id)
15
15
  end
16
16
 
17
17
  # Returns the user currently editing this page.
18
18
  #
19
19
  def locker
20
- Alchemy.user_class.try(:find_by, {id: locked_by})
20
+ get_page_user(locked_by)
21
21
  end
22
22
 
23
23
  # Returns the name of the creator of this page.
@@ -47,5 +47,12 @@ module Alchemy
47
47
  (locker && locker.try(:name)) || I18n.t('unknown')
48
48
  end
49
49
 
50
+ private
51
+
52
+ def get_page_user(id)
53
+ if Alchemy.user_class.respond_to? :primary_key
54
+ Alchemy.user_class.try(:find_by, {Alchemy.user_class.primary_key => id})
55
+ end
56
+ end
50
57
  end
51
58
  end
@@ -62,10 +62,21 @@ module Alchemy
62
62
 
63
63
  stampable stamper_class_name: Alchemy.user_class_name
64
64
 
65
- scope :named, ->(name) { where("name LIKE ?", "%#{name}%") }
66
- scope :recent, -> { where("#{self.table_name}.created_at > ?", Time.now - 24.hours).order(:created_at) }
67
- scope :deletable, -> { where('alchemy_pictures.id NOT IN (SELECT picture_id FROM alchemy_essence_pictures)') }
68
- scope :without_tag, -> { where("cached_tag_list IS NULL OR cached_tag_list = ''") }
65
+ scope :named, ->(name) {
66
+ where("#{self.table_name}.name LIKE ?", "%#{name}%")
67
+ }
68
+
69
+ scope :recent, -> {
70
+ where("#{self.table_name}.created_at > ?", Time.now - 24.hours).order(:created_at)
71
+ }
72
+
73
+ scope :deletable, -> {
74
+ where("#{self.table_name}.id NOT IN (SELECT picture_id FROM alchemy_essence_pictures)")
75
+ }
76
+
77
+ scope :without_tag, -> {
78
+ where("#{self.table_name}.cached_tag_list IS NULL OR #{self.table_name}.cached_tag_list = ''")
79
+ }
69
80
 
70
81
  after_update :touch_contents
71
82
 
@@ -73,8 +84,21 @@ module Alchemy
73
84
 
74
85
  class << self
75
86
 
87
+ # Returns filtered, paginated and ordered picture collection.
76
88
  def find_paginated(params, per_page)
77
- Picture.named(params[:query]).page(params[:page] || 1).per(per_page).order(:name)
89
+ @pictures = Picture.all
90
+
91
+ if params[:tagged_with].present?
92
+ @pictures = @pictures.tagged_with(params[:tagged_with])
93
+ end
94
+ if params[:filter].present?
95
+ @pictures = @pictures.filtered_by(params[:filter])
96
+ end
97
+ if params[:query].present?
98
+ @pictures = @pictures.named(params[:query])
99
+ end
100
+
101
+ @pictures.page(params[:page] || 1).per(per_page).order(:name)
78
102
  end
79
103
 
80
104
  def last_upload
@@ -92,7 +116,6 @@ module Alchemy
92
116
  all
93
117
  end
94
118
  end
95
-
96
119
  end
97
120
 
98
121
  # Instance methods
@@ -173,17 +173,24 @@ module Alchemy
173
173
  # This function takes a target and a base dimensions hash and returns
174
174
  # the dimensions of the image when the base dimensions hash fills
175
175
  # the target.
176
+ #
176
177
  # Aspect ratio will be preserved.
177
178
  #
178
179
  def size_when_fitting(target, dimensions = get_base_dimensions)
179
- zoom_x = dimensions[:width].to_f / target[:width]
180
- zoom_y = dimensions[:height].to_f / target[:height]
180
+ zoom = [
181
+ dimensions[:width].to_f / target[:width],
182
+ dimensions[:height].to_f / target[:height]
183
+ ].max
184
+
185
+ if zoom == 0.0
186
+ width = target[:width]
187
+ height = target[:height]
188
+ else
189
+ width = (dimensions[:width] / zoom).round
190
+ height = (dimensions[:height] / zoom).round
191
+ end
181
192
 
182
- zoom = [zoom_x, zoom_y].max
183
- {
184
- width: (dimensions[:width] / zoom).round.to_i,
185
- height: (dimensions[:height] / zoom).round.to_i
186
- }
193
+ {width: width.to_i, height: height.to_i}
187
194
  end
188
195
 
189
196
  # Given a point as a Hash with :x and :y, and a mask with