locomotive_cms 2.5.6 → 2.5.7

Sign up to get free protection for your applications and to get access to all the features.
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