locomotive_cms 2.5.6 → 2.5.7

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +7 -3
  3. data/app/assets/javascripts/locomotive/utils/tinymce_settings.js.coffee +4 -3
  4. data/app/assets/javascripts/locomotive/views/pages/_form_view.js.coffee +2 -2
  5. data/app/assets/stylesheets/locomotive/backoffice/application.css.scss +34 -1
  6. data/app/controllers/locomotive/api/base_controller.rb +8 -0
  7. data/app/controllers/locomotive/api/content_entries_controller.rb +15 -2
  8. data/app/controllers/locomotive/api/my_account_controller.rb +15 -0
  9. data/app/controllers/locomotive/api/version_controller.rb +17 -0
  10. data/app/controllers/locomotive/base_controller.rb +1 -1
  11. data/app/controllers/locomotive/content_entries_controller.rb +9 -10
  12. data/app/helpers/locomotive/content_types_helper.rb +16 -1
  13. data/app/helpers/locomotive/pages_helper.rb +13 -1
  14. data/app/models/locomotive/content_type.rb +15 -8
  15. data/app/models/locomotive/extensions/page/layout.rb +42 -0
  16. data/app/models/locomotive/extensions/page/templatized.rb +1 -1
  17. data/app/models/locomotive/page.rb +1 -0
  18. data/app/presenters/locomotive/content_entry_presenter.rb +5 -1
  19. data/app/presenters/locomotive/page_presenter.rb +1 -1
  20. data/app/services/locomotive/content_entry_service.rb +81 -0
  21. data/app/uploaders/locomotive/theme_asset_uploader.rb +1 -1
  22. data/app/views/locomotive/content_entries/index.html.haml +8 -0
  23. data/app/views/locomotive/content_types/_form.html.haml +2 -0
  24. data/app/views/locomotive/notifications/new_content_entry.html.haml +2 -2
  25. data/app/views/locomotive/pages/_form.html.haml +8 -1
  26. data/config/locales/admin_ui.en.yml +2 -0
  27. data/config/locales/admin_ui.fr.yml +1 -0
  28. data/config/locales/formtastic.en.yml +3 -0
  29. data/config/routes.rb +6 -2
  30. data/features/api/content_entries.feature +22 -9
  31. data/features/backoffice/site.feature +1 -1
  32. data/features/public/content_entries.feature +20 -5
  33. data/features/step_definitions/content_types_steps.rb +6 -0
  34. data/lib/generators/locomotive/install/templates/devise.rb +0 -2
  35. data/lib/locomotive/action_controller/responder.rb +1 -1
  36. data/lib/locomotive/carrierwave.rb +1 -0
  37. data/lib/locomotive/carrierwave/asset.rb +1 -1
  38. data/lib/locomotive/httparty/webservice.rb +17 -11
  39. data/lib/locomotive/liquid/drops/content_types.rb +7 -1
  40. data/lib/locomotive/liquid/drops/page.rb +51 -3
  41. data/lib/locomotive/liquid/tags/consume.rb +15 -10
  42. data/lib/locomotive/liquid/tags/editable/base.rb +1 -1
  43. data/lib/locomotive/liquid/tags/with_scope.rb +6 -1
  44. data/lib/locomotive/presentable.rb +1 -1
  45. data/lib/locomotive/regexps.rb +1 -1
  46. data/lib/locomotive/version.rb +1 -1
  47. data/lib/tasks/locomotive.rake +1 -1
  48. data/spec/dummy/config/application.rb +1 -1
  49. data/spec/dummy/config/mongoid.yml +2 -2
  50. data/spec/lib/locomotive/httparty/webservice_spec.rb +8 -3
  51. data/spec/lib/locomotive/liquid/drops/page_spec.rb +20 -5
  52. data/spec/lib/locomotive/liquid/tags/consume_spec.rb +66 -48
  53. data/spec/lib/locomotive/liquid/tags/with_scope_spec.rb +6 -0
  54. data/spec/mailers/locomotive/notifications_spec.rb +15 -8
  55. data/spec/models/locomotive/content_entry_spec.rb +1 -1
  56. data/spec/models/locomotive/editable_control_spec.rb +2 -2
  57. data/spec/models/locomotive/extensions/page/layout_spec.rb +50 -0
  58. data/spec/models/locomotive/site_spec.rb +1 -1
  59. metadata +26 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5dfbff0cc38b5176c19758fbfc3f62445f568dd7
4
- data.tar.gz: a3cbab7b3f997330faa9d3be3cd19102b4f4594e
3
+ metadata.gz: 1b1e10abc04c335552fd44727e7aee6af1ad1d6d
4
+ data.tar.gz: 2472daa204aa2cfb17d1631ba2a24f51e2d5ef75
5
5
  SHA512:
6
- metadata.gz: 027015441876276ed84f1a4bd441f92e8c2f4b8e6ccae09321eeecf1bf762ec0e6f61cfeb3d0bf8a8a1d205dd3fed985dbdd3e0c4895efb4ead37afc0ab33438
7
- data.tar.gz: fb8250bc13cb6e7e174967e11d91fc5061484f5cd1632f215a8612c2b6db114516fd9aa2fb593876d4e6eceb7d3e284f7bab3a4112a40d1761280ee79094343a
6
+ metadata.gz: bfeba1baa372344dd774f12c82ba6585ce3fe036befc1482fed64053e0729f8fc44523427573833896636ca69e4f56f164ab450c3bf9fec220144cf5b6570d09
7
+ data.tar.gz: dfa3a093037b69b739486d26721a9cf32f17a5bce994ce73126afcf12a2469185320e73ba6a635fbdcbf774a051de067b48d0967d01cb380aa3aebd4d8911391
data/Gemfile CHANGED
@@ -14,6 +14,8 @@ end
14
14
  # The rest of the dependencies are for use when in the locomotive development / test environments
15
15
 
16
16
  group :test, :development do
17
+
18
+ gem 'test-unit'
17
19
  gem 'rspec-rails', '~> 2.13.0' # In order to have rspec tasks and generators
18
20
  gem 'rspec-cells', '0.1.10'
19
21
  end
@@ -30,6 +32,8 @@ group :development do
30
32
 
31
33
  # gem 'carrierwave-mongoid', git: 'git://github.com/locomotivecms/carrierwave-mongoid.git'
32
34
 
35
+ gem 'eventmachine', '~> 1.0.4'
36
+
33
37
  gem 'thor'
34
38
  gem 'github_api'
35
39
 
@@ -42,8 +46,8 @@ group :test do
42
46
 
43
47
  gem 'cucumber-rails', require: false
44
48
 
45
- # gem 'autotest', platforms: :mri
46
- # gem 'ZenTest', platforms: :mri
49
+ gem 'autotest', platforms: :mri
50
+ gem 'ZenTest', platforms: :mri
47
51
 
48
52
  gem 'poltergeist', '~> 1.1.0'
49
53
  gem 'shoulda-matchers', '~> 1.5.2'
@@ -59,5 +63,5 @@ group :test do
59
63
 
60
64
  gem 'mocha', '~> 0.13.0', require: false
61
65
 
62
- # gem 'debugger', git: 'git://github.com/cldwalker/debugger.git'
66
+ gem 'debugger', git: 'git://github.com/cldwalker/debugger.git'
63
67
  end
@@ -4,7 +4,6 @@ window.Locomotive.tinyMCE =
4
4
  theme: 'advanced'
5
5
  skin: 'locomotive'
6
6
  plugins: 'safari,jqueryinlinepopups,table,locomotive_media,fullscreen,paste'
7
- extended_valid_elements: 'iframe[width|height|frameborder|allowfullscreen|src|title]'
8
7
  theme_advanced_buttons1: 'fullscreen,code,|,bold,italic,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,|,outdent,indent,blockquote,|,link,unlink,|,table,|,locomotive_media,|,pasteword'
9
8
  theme_advanced_buttons2: 'formatselect,fontselect,fontsizeselect'
10
9
  theme_advanced_buttons3: ''
@@ -16,6 +15,7 @@ window.Locomotive.tinyMCE =
16
15
  fullscreen_new_window: false
17
16
  fullscreen_settings:
18
17
  theme_advanced_path_location: 'top'
18
+ extended_valid_elements: 'iframe[width|height|frameborder|allowfullscreen|src|title],img[src|alt|title|height|usemap|hspace|vspace|border|onmouseover|onmouseout|name|width|style|class|align|id],figure[width|style|class|align|id],figcaption[style|class],font[class|color|face|id|lang|size|style|title],u,strong/b'
19
19
 
20
20
  minimalSettings:
21
21
  theme: 'advanced'
@@ -35,12 +35,12 @@ window.Locomotive.tinyMCE =
35
35
  forced_root_block: false
36
36
  force_br_newlines: true
37
37
  force_p_newlines: false
38
+ extended_valid_elements: 'iframe[width|height|frameborder|allowfullscreen|src|title],img[src|alt|title|height|usemap|hspace|vspace|border|onmouseover|onmouseout|name|width|style|class|align|id],figure[width|style|class|align|id],figcaption[style|class],font[class|color|face|id|lang|size|style|title],u,strong/b'
38
39
 
39
40
  popupSettings:
40
41
  theme: 'advanced'
41
42
  skin: 'locomotive'
42
43
  plugins: 'safari,jqueryinlinepopups,locomotive_media,fullscreen,paste'
43
- extended_valid_elements: 'iframe[width|height|frameborder|allowfullscreen|src|title]'
44
44
  theme_advanced_buttons1: 'fullscreen,code,|,bold,italic,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,|,outdent,indent,blockquote,|,link,unlink,|,locomotive_media,|,pasteword'
45
45
  theme_advanced_buttons2: 'formatselect,fontselect,fontsizeselect'
46
46
  theme_advanced_buttons3: ''
@@ -51,4 +51,5 @@ window.Locomotive.tinyMCE =
51
51
  convert_urls: false
52
52
  fullscreen_new_window: false
53
53
  fullscreen_settings:
54
- theme_advanced_path_location: 'top'
54
+ theme_advanced_path_location: 'top'
55
+ extended_valid_elements: 'iframe[width|height|frameborder|allowfullscreen|src|title],img[src|alt|title|height|usemap|hspace|vspace|border|onmouseover|onmouseout|name|width|style|class|align|id],figure[width|style|class|align|id],figcaption[style|class],font[class|color|face|id|lang|size|style|title],u,strong/b'
@@ -93,7 +93,7 @@ class Locomotive.Views.Pages.FormView extends Locomotive.Views.Shared.FormView
93
93
  @editor.on 'change', (editor, change) => @model.set(raw_template: editor.getValue())
94
94
 
95
95
  after_inputs_fold: ->
96
- @editor.refresh()
96
+ @editor.refresh() if @editor?
97
97
 
98
98
  render_editable_elements: ->
99
99
  @$('.formtastic fieldset.inputs:first').before(@editable_elements_view.render().el)
@@ -160,4 +160,4 @@ class Locomotive.Views.Pages.FormView extends Locomotive.Views.Shared.FormView
160
160
 
161
161
  enable_other_checkboxes: ->
162
162
  @$('li.toggle input[type=checkbox].simple-toggle').checkToggle()
163
- @$('li.toggle.simple-toggle input[type=checkbox]').checkToggle()
163
+ @$('li.toggle.simple-toggle input[type=checkbox]').checkToggle()
@@ -366,4 +366,37 @@ p span.code {
366
366
  height: auto;
367
367
  }
368
368
  }
369
- }
369
+ }
370
+
371
+ /* ___ search box (content_entries) ___ */
372
+
373
+ .search-box {
374
+ float: right;
375
+ margin-bottom: 15px;
376
+
377
+ form {
378
+ display: inline-block;
379
+ @include border-radius(16px);
380
+ border: 4px solid #cbcbcb;
381
+ line-height: 20px;
382
+
383
+ .icon-search {
384
+ position: relative;
385
+ top: 2px;
386
+ margin-left: 10px;
387
+ color: #8b8d9a;
388
+ font-size: 18px;
389
+ }
390
+
391
+ input[type=text] {
392
+ display: inline-block;
393
+ min-width: 240px;
394
+ margin: 0 10px 0 6px;
395
+ line-height: 20px;
396
+ border: none;
397
+ font-size: 13px;
398
+ color: #8b8d9a;
399
+ font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
400
+ }
401
+ }
402
+ }
@@ -39,6 +39,14 @@ module Locomotive
39
39
  authenticate_locomotive_account!
40
40
  end
41
41
 
42
+ def require_site
43
+ return true if current_site
44
+
45
+ render_no_site_error
46
+
47
+ false # halt chain
48
+ end
49
+
42
50
  def set_locale
43
51
  locale = params[:locale] ||
44
52
  current_site.try(:default_locale) ||
@@ -10,8 +10,8 @@ module Locomotive
10
10
  })
11
11
 
12
12
  def index
13
- @content_entries = @content_entries.order_by([get_content_type.order_by_definition])
14
- respond_with @content_entries
13
+ @content_entries = service.all(params.slice(:page, :per_page, :order_by, :where))
14
+ respond_with(@content_entries)
15
15
  end
16
16
 
17
17
  def show
@@ -35,12 +35,25 @@ module Locomotive
35
35
  respond_with @content_entry, location: main_app.locomotive_api_content_entries_url(@content_type.slug)
36
36
  end
37
37
 
38
+ def destroy_all
39
+ service.destroy_all
40
+ respond_to do |format|
41
+ format.html { render text: true }
42
+ format.json { render json: { success: true } }
43
+ format.xml { render xml: { success: true } }
44
+ end
45
+ end
46
+
38
47
  protected
39
48
 
40
49
  def get_content_type
41
50
  @content_type ||= current_site.content_types.by_id_or_slug(params[:slug]).first
42
51
  end
43
52
 
53
+ def service
54
+ @service ||= Locomotive::ContentEntryService.new(get_content_type)
55
+ end
56
+
44
57
  end
45
58
  end
46
59
  end
@@ -6,10 +6,25 @@ module Locomotive
6
6
 
7
7
  skip_before_filter :require_site, :set_locale, :set_current_thread_variables
8
8
 
9
+ skip_before_filter :require_account, only: [:create]
10
+
9
11
  def show
10
12
  respond_with(current_locomotive_account)
11
13
  end
12
14
 
15
+ def create
16
+ @account = Locomotive::Account.new
17
+ @account.from_presenter(params[:account])
18
+ @account.save
19
+ respond_with(@account)
20
+ end
21
+
22
+ def update
23
+ current_locomotive_account.from_presenter(params[:account])
24
+ current_locomotive_account.save
25
+ respond_with(current_locomotive_account)
26
+ end
27
+
13
28
  protected
14
29
 
15
30
  def self.description
@@ -0,0 +1,17 @@
1
+ module Locomotive
2
+ module Api
3
+ class VersionController < ApplicationController
4
+
5
+ skip_before_filter :require_account, :require_site, :set_current_thread_variables
6
+
7
+ def show
8
+ respond_to do |format|
9
+ format.html { render text: Locomotive::VERSION }
10
+ format.json { render json: { engine: Locomotive::VERSION } }
11
+ format.xml { render xml: { engine: Locomotive::VERSION } }
12
+ end
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -64,4 +64,4 @@ module Locomotive
64
64
  end
65
65
 
66
66
  end
67
- end
67
+ end
@@ -7,7 +7,7 @@ module Locomotive
7
7
 
8
8
  before_filter :back_to_default_site_locale, only: %w(new create)
9
9
 
10
- before_filter :set_content_type
10
+ before_filter :get_content_type
11
11
 
12
12
  skip_load_and_authorize_resource
13
13
 
@@ -18,13 +18,8 @@ module Locomotive
18
18
  respond_to :csv, only: [:export]
19
19
 
20
20
  def index
21
- options = { page: params[:page] || 1, per_page: Locomotive.config.ui[:per_page] }
22
- @content_entries = if params[:q]
23
- @content_type.ordered_entries(options.merge(q: params[:q]))
24
- else
25
- @content_type.list_or_group_entries(options)
26
- end
27
- respond_with @content_entries
21
+ @content_entries = service.all(params.slice(:page, :per_page, :q, :where))
22
+ respond_with @content_entries, html_view: true
28
23
  end
29
24
 
30
25
  def export
@@ -76,13 +71,17 @@ module Locomotive
76
71
 
77
72
  protected
78
73
 
79
- def set_content_type
74
+ def get_content_type
80
75
  @content_type ||= current_site.content_types.by_id_or_slug(params[:slug]).first
81
76
  end
82
77
 
78
+ def service
79
+ @service ||= Locomotive::ContentEntryService.new(get_content_type)
80
+ end
81
+
83
82
  def authorize_content
84
83
  authorize! params[:action].to_sym, ContentEntry
85
84
  end
86
85
 
87
86
  end
88
- end
87
+ end
@@ -69,5 +69,20 @@ module Locomotive
69
69
  end
70
70
  end
71
71
 
72
+ # List the fields which could be used to filter the content entries
73
+ # in the back-office.
74
+ # Not all the types are included. Only: string, text, integer, float, email
75
+ #
76
+ # @param [ ContentType ] content_type The content type owning the fields
77
+ #
78
+ # @return [ Array ] Used as it by the select_tag method
79
+ #
80
+ def options_for_filter_fields(content_type)
81
+ allowed_types = %w(string text integer float email)
82
+ fields = content_type.entries_custom_fields.where(:type.in => allowed_types)
83
+
84
+ fields.map { |field| [field.label, field._id] }
85
+ end
86
+
72
87
  end
73
- end
88
+ end
@@ -36,6 +36,18 @@ module Locomotive
36
36
  list
37
37
  end
38
38
 
39
+ def display_page_layouts?
40
+ ((@page.persisted? && @page.allow_layout?) || !@page.persisted?) &&
41
+ !current_site.pages.layouts.empty?
42
+ end
43
+
44
+ def options_for_page_layouts
45
+ layouts = current_site.pages.layouts.map do |_layout|
46
+ [_layout.title, _layout._id]
47
+ end
48
+ [[t('.no_layout'), nil]] + layouts
49
+ end
50
+
39
51
  def options_for_target_klass_name
40
52
  base_models = current_site.content_types.map do |type|
41
53
  [type.name.humanize, type.klass_with_custom_fields(:entries)]
@@ -90,4 +102,4 @@ module Locomotive
90
102
  end
91
103
 
92
104
  end
93
- end
105
+ end
@@ -20,6 +20,7 @@ module Locomotive
20
20
  field :order_direction, default: 'asc'
21
21
  field :public_submission_enabled, type: Boolean, default: false
22
22
  field :public_submission_accounts, type: Array
23
+ field :filter_fields, type: Array
23
24
 
24
25
  ## associations ##
25
26
  belongs_to :site, class_name: 'Locomotive::Site', validate: false
@@ -50,6 +51,7 @@ module Locomotive
50
51
  ## callbacks ##
51
52
  before_validation :normalize_slug
52
53
  before_validation :sanitize_public_submission_accounts
54
+ before_validation :sanitize_filter_fields
53
55
  after_validation :bubble_fields_errors_up
54
56
  before_update :update_label_field_name_in_entries
55
57
 
@@ -80,25 +82,21 @@ module Locomotive
80
82
  # Order the list of entries, paginate it if requested
81
83
  # and filter it.
82
84
  #
83
- # @param [ Hash ] options Options to filter and paginate.
85
+ # @param [ Hash ] options Options to filter (where key), order (order_by key) and paginate (page, per_page keys)
84
86
  #
85
87
  # @return [ Criteria ] A Mongoid criteria if not paginated (array otherwise).
86
88
  #
87
89
  def ordered_entries(options = nil)
88
90
  options ||= {}
89
91
 
92
+ # pagination
90
93
  page, per_page = options.delete(:page), options.delete(:per_page)
91
94
 
92
- # search for a label
93
- if options[:q]
94
- options[label_field_name.to_sym] = /#{options.delete(:q)}/i
95
- end
96
-
97
95
  # order list
98
96
  _order_by_definition = (options || {}).delete(:order_by).try(:split) || self.order_by_definition
99
97
 
100
98
  # get list
101
- _entries = self.entries.order_by([_order_by_definition]).where(options)
99
+ _entries = self.entries.order_by([_order_by_definition]).where(options[:where] || {})
102
100
 
103
101
  # pagination or full list
104
102
  !self.order_manually? && page ? _entries.page(page).per(per_page) : _entries
@@ -236,6 +234,13 @@ module Locomotive
236
234
  end
237
235
  end
238
236
 
237
+ # We do not want to have a blank value in the list of fields used to filter the entries.
238
+ def sanitize_filter_fields
239
+ if self.filter_fields
240
+ self.filter_fields.reject! { |id| id.blank? }
241
+ end
242
+ end
243
+
239
244
  def bubble_fields_errors_up
240
245
  return if self.errors[:entries_custom_fields].empty?
241
246
 
@@ -263,7 +268,9 @@ module Locomotive
263
268
  def ensure_class_name_security(field)
264
269
  if field.class_name =~ /^Locomotive::ContentEntry([a-z0-9]+)$/
265
270
  # if the content type does not exist (anymore), bypass the security checking
266
- content_type = Locomotive::ContentType.find($1) rescue return
271
+ content_type = Locomotive::ContentType.find($1) rescue nil
272
+
273
+ return if content_type.nil?
267
274
 
268
275
  if content_type.site_id != self.site_id
269
276
  field.errors.add :class_name, :security
@@ -0,0 +1,42 @@
1
+ module Locomotive
2
+ module Extensions
3
+ module Page
4
+ module Layout
5
+
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+
10
+ ## fields ##
11
+ field :is_layout, type: Boolean, default: false
12
+ field :allow_layout, type: Boolean, default: ->{ new_record? }
13
+
14
+ ## associations ##
15
+ belongs_to :layout, class_name: 'Locomotive::Page', inverse_of: :layout_children, validate: false
16
+ has_many :layout_children, class_name: 'Locomotive::Page', inverse_of: :layout
17
+
18
+ ## callbacks ##
19
+ before_validation :set_default_raw_template_if_layout
20
+
21
+ ## scopes ##
22
+ scope :layouts, where(is_layout: true)
23
+
24
+ end
25
+
26
+ private
27
+
28
+ def set_default_raw_template_if_layout
29
+ return true unless self.allow_layout?
30
+
31
+ if self.layout
32
+ self.raw_template = %({% extends "#{self.layout.fullpath}" %})
33
+ elsif self.layout_id_was
34
+ # use case: layout -> no layout
35
+ self.raw_template = nil
36
+ end
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end