browsercms 3.3.2 → 3.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/app/controllers/cms/content_block_controller.rb +2 -2
  2. data/app/controllers/cms/content_controller.rb +1 -1
  3. data/app/controllers/cms/section_nodes_controller.rb +6 -1
  4. data/app/controllers/cms/sections_controller.rb +1 -1
  5. data/app/helpers/cms/application_helper.rb +1 -1
  6. data/app/helpers/cms/content_block_helper.rb +27 -0
  7. data/app/helpers/cms/section_nodes_helper.rb +43 -5
  8. data/app/models/abstract_file_block.rb +17 -2
  9. data/app/models/attachment.rb +16 -34
  10. data/app/models/file_block.rb +0 -12
  11. data/app/models/image_block.rb +0 -12
  12. data/app/models/link.rb +4 -21
  13. data/app/models/page.rb +36 -35
  14. data/app/models/section.rb +82 -42
  15. data/app/models/section_node.rb +41 -24
  16. data/app/views/cms/blocks/index.html.erb +4 -4
  17. data/app/views/cms/file_blocks/_form.html.erb +1 -1
  18. data/app/views/cms/image_blocks/_form.html.erb +1 -1
  19. data/app/views/cms/section_nodes/_link.html.erb +6 -3
  20. data/app/views/cms/section_nodes/_node.html.erb +11 -2
  21. data/app/views/cms/section_nodes/_page.html.erb +13 -7
  22. data/app/views/cms/section_nodes/_section.html.erb +24 -8
  23. data/app/views/cms/section_nodes/index.html.erb +18 -6
  24. data/app/views/cms/shared/_pagination.html.erb +4 -4
  25. data/app/views/portlets/reset_password/render.html.erb +0 -2
  26. data/browsercms.gemspec +1 -4
  27. data/db/migrate/20100117144039_browsercms315.rb +94 -0
  28. data/lib/acts_as_list.rb +1 -1
  29. data/lib/browsercms.rb +3 -1
  30. data/lib/cms/addressable.rb +83 -0
  31. data/lib/cms/behaviors/attaching.rb +42 -24
  32. data/lib/cms/behaviors/connecting.rb +2 -1
  33. data/lib/cms/behaviors/publishing.rb +12 -3
  34. data/lib/cms/behaviors/versioning.rb +43 -24
  35. data/lib/cms/content_rendering_support.rb +3 -3
  36. data/lib/cms/error_pages.rb +8 -0
  37. data/lib/cms/version.rb +2 -2
  38. data/lib/generators/browser_cms/cms/cms_generator.rb +1 -0
  39. data/lib/generators/cms/upgrade_module/templates/GPL.txt +1 -1
  40. data/lib/tasks/data.rake +43 -0
  41. metadata +27 -8
  42. data/app/views/cms/section_nodes/_section_node.html.erb +0 -10
data/lib/browsercms.rb CHANGED
@@ -2,6 +2,8 @@ require 'cms/engine'
2
2
  require 'cms/extensions'
3
3
  require 'cms/routes'
4
4
  require 'cms/caching'
5
+ require 'cms/addressable'
6
+ require 'cms/error_pages'
5
7
 
6
8
  #Load libraries that are included with CMS
7
9
  require 'acts_as_list'
@@ -15,4 +17,4 @@ require 'cms/date_picker'
15
17
  require 'cms/content_rendering_support'
16
18
 
17
19
  # This shouldn't be necessary, except for the need to get into the loadpath for testing.
18
- require 'command_line'
20
+ require 'command_line'
@@ -0,0 +1,83 @@
1
+ # Represents any object which exists in a Sitemap.
2
+ #
3
+ # Can have parents (using SectionNodes) and children.
4
+ module Addressable
5
+
6
+ # Returns a list of all Addressable objects that are ancestors to this record.
7
+ # @param [Hash] options
8
+ # @option [Symbol] :include_self If this object should be included in the Array
9
+ # @return [Array<Addressable]
10
+ #
11
+ def ancestors(options={})
12
+ ancestor_nodes = node.ancestors
13
+ ancestors = ancestor_nodes.collect { |node| node.node }
14
+ ancestors << self if options[:include_self]
15
+ ancestors
16
+ end
17
+
18
+ def parent
19
+ @parent if @parent
20
+ node ? node.section : nil
21
+ end
22
+
23
+ def cache_parent(section)
24
+ @parent = section
25
+ end
26
+
27
+ def parent=(sec)
28
+ if node
29
+ node.move_to_end(sec)
30
+ else
31
+ build_section_node(:node => self, :section => sec)
32
+ end
33
+ end
34
+
35
+ # Computes the name of the partial used to render this object in the sitemap.
36
+ def partial_for
37
+ self.class.name.underscore
38
+ end
39
+
40
+ # Pages/Links/Attachments use their parent to determine access
41
+ module LeafNode
42
+ def access_status
43
+ parent.status
44
+ end
45
+ end
46
+
47
+ module NodeAccessors
48
+ def node
49
+ section_node
50
+ end
51
+
52
+ def node=(n)
53
+ self.section_node = n
54
+ end
55
+ end
56
+ # These exist for backwards compatibility to avoid having to change tests.
57
+ # I want to get rid of these in favor of parent and parent_id
58
+ module DeprecatedPageAccessors
59
+ include LeafNode
60
+ include NodeAccessors
61
+
62
+ def build_node(opts)
63
+ build_section_node(opts)
64
+ end
65
+
66
+ def section_id
67
+ section ? section.id : nil
68
+ end
69
+
70
+ def section_id=(sec_id)
71
+ self.section = Section.find(sec_id)
72
+ end
73
+
74
+ def section
75
+ parent
76
+ end
77
+
78
+ def section=(sec)
79
+ self.parent = sec
80
+
81
+ end
82
+ end
83
+ end
@@ -1,34 +1,36 @@
1
1
  module Cms
2
2
  module Behaviors
3
3
  module Attaching
4
- SANITIZATION_REGEXES = [ [/\s/, '_'], [/[&+()]/, '-'], [/[=?!'"{}\[\]#<>%]/, ''] ]
5
-
4
+ SANITIZATION_REGEXES = [[/\s/, '_'], [/[&+()]/, '-'], [/[=?!'"{}\[\]#<>%]/, '']]
5
+
6
6
  def self.included(model_class)
7
7
  model_class.extend(MacroMethods)
8
8
  end
9
- module MacroMethods
9
+
10
+ module MacroMethods
10
11
  def belongs_to_attachment?
11
12
  !!@belongs_to_attachment
12
13
  end
14
+
13
15
  def belongs_to_attachment(options={})
14
16
  @belongs_to_attachment = true
15
17
  include InstanceMethods
16
- before_validation :process_attachment
18
+ before_validation :process_attachment
17
19
  before_save :update_attachment_if_changed
18
20
  after_save :clear_attachment_ivars
19
- belongs_to :attachment, :dependent => :destroy
20
-
21
+ belongs_to :attachment, :dependent => :destroy
22
+
21
23
  validates_each :attachment_file do |record, attr, value|
22
24
  if record.attachment && !record.attachment.valid?
23
25
  record.attachment.errors.each do |err_field, err_value|
24
26
  if err_field.to_sym == :file_path
25
27
  record.errors.add(:attachment_file_path, err_value)
26
- else
28
+ else
27
29
  record.errors.add(:attachment_file, err_value)
28
30
  end
29
- end
31
+ end
30
32
  end
31
- end
33
+ end
32
34
  end
33
35
  end
34
36
  module InstanceMethods
@@ -93,22 +95,30 @@ module Cms
93
95
  unless attachment_section_id.blank?
94
96
  errors.add(:attachment_file, "You must upload a file")
95
97
  return false
96
- end
98
+ end
97
99
  else
98
100
  build_attachment if attachment.nil?
99
101
  attachment.temp_file = attachment_file
100
- Rails.logger.warn "After attachment (#{attachment.temp_file})"
101
-
102
- set_attachment_file_path
102
+ handle_setting_attachment_path
103
103
  if attachment.file_path.blank?
104
104
  errors.add(:attachment_file_path, "File Name is required for attachment")
105
105
  return false
106
106
  end
107
- set_attachment_section
108
- if attachment.section_id.blank?
107
+ handle_setting_attachment_section
108
+ unless attachment.section
109
109
  errors.add(:attachment_file, "Section is required for attachment")
110
110
  return false
111
111
  end
112
+
113
+ end
114
+ end
115
+
116
+ # Define at :set_attachment_path if you would like to override the way file_path is set
117
+ def handle_setting_attachment_path
118
+ if self.respond_to? :set_attachment_path
119
+ set_attachment_path
120
+ else
121
+ use_default_attachment_path
112
122
  end
113
123
  end
114
124
 
@@ -116,18 +126,26 @@ module Cms
116
126
  @attachment_file = nil
117
127
  @attachment_file_path = nil
118
128
  @attachment_section_id = nil
119
- @attachment_section = nil
129
+ @attachment_section = nil
120
130
  end
121
131
 
122
- # Override this method if you would like to override the way the section is set
123
- def set_attachment_section
132
+ # Implement a :set_attachment_section method if you would like to override the way the section is set
133
+ def handle_setting_attachment_section
134
+ if self.respond_to? :set_attachment_section
135
+ set_attachment_section
136
+ else
137
+ use_default_attachment_section
138
+ end
139
+ end
140
+
141
+ # Default behavior for assigning a section, if a block does not define its own.
142
+ def use_default_attachment_section
124
143
  if !attachment_file.blank?
125
144
  attachment.section = Section.root.first
126
145
  end
127
146
  end
128
147
 
129
- # Override this method if you would like to override the way file_path is set
130
- def set_attachment_file_path
148
+ def use_default_attachment_path
131
149
  if !attachment_file.blank?
132
150
  attachment.file_path = "/attachments/#{File.basename(attachment_file.original_filename).to_s.downcase}"
133
151
  end
@@ -173,16 +191,16 @@ module Cms
173
191
  (published? && live_version?) ? attachment_file_path : "/cms/attachments/#{attachment_id}?version=#{attachment_version}"
174
192
  else
175
193
  nil
176
- end
194
+ end
177
195
  end
178
-
196
+
179
197
  # Forces this record to be changed, even if nothing has changed
180
198
  # This is necessary if just the section.id has changed, for example
181
199
  def dirty!
182
200
  # Seems like a hack, is there a better way?
183
201
  self.updated_at = Time.now
184
- end
185
-
202
+ end
203
+
186
204
  end
187
205
  end
188
206
  end
@@ -41,7 +41,8 @@ module Cms
41
41
  module InstanceMethods
42
42
 
43
43
  def connected_pages
44
- Page.currently_connected_to(self)
44
+ return @connected_pages if @connected_pages
45
+ @connected_pages = Page.connected_to(self)
45
46
  end
46
47
 
47
48
  def connected_page_count
@@ -125,15 +125,24 @@ module Cms
125
125
  end
126
126
 
127
127
  def status
128
- live? ? :published : :draft
129
- end
128
+ return @status if @status
129
+ @status = live? ? :published : :draft
130
+ end
130
131
 
131
132
  def status_name
132
133
  status.to_s.titleize
133
134
  end
134
135
 
135
136
  def live?
136
- self.class.versioned? ? live_version.version == draft.version && published? : true
137
+ if self.class.versioned?
138
+ if (respond_to?(:latest_version) && self.latest_version)
139
+ version == latest_version && published?
140
+ else
141
+ live_version.version == draft.version && published?
142
+ end
143
+ else
144
+ true
145
+ end
137
146
  end
138
147
 
139
148
  end
@@ -39,7 +39,8 @@ module Cms
39
39
  extend ClassMethods
40
40
  include InstanceMethods
41
41
 
42
- has_many :versions, :class_name => version_class_name, :foreign_key => version_foreign_key
42
+ has_many :versions, :class_name => version_class_name, :foreign_key => version_foreign_key
43
+ after_save :update_latest_version
43
44
 
44
45
  before_validation :initialize_version
45
46
  before_save :build_new_version
@@ -93,7 +94,7 @@ module Cms
93
94
 
94
95
  def versioned_columns
95
96
  @versioned_columns ||= (version_class.new.attributes.keys -
96
- (%w[ id lock_version position version_comment created_at updated_at created_by_id updated_by_id type ] + [version_foreign_key]))
97
+ (%w[id lock_version position version_comment created_at updated_at created_by_id updated_by_id type] + [version_foreign_key]))
97
98
  end
98
99
  end
99
100
  module InstanceMethods
@@ -101,6 +102,15 @@ module Cms
101
102
  self.version = 1 if new_record?
102
103
  end
103
104
 
105
+ # Used in migrations and as a callback.
106
+ def update_latest_version
107
+ #Rails 3 could use update_column here instead
108
+ if respond_to? :latest_version
109
+ sql = "UPDATE #{self.class.table_name} SET latest_version = #{draft.version} where id = #{self.id}"
110
+ connection.execute sql
111
+ self.latest_version = draft.version # So we don't need to #reload this object. Probably marks it as dirty though, which could have weird side effects.
112
+ end
113
+ end
104
114
 
105
115
  def build_new_version_and_add_to_versions_list_for_saving
106
116
  # First get the values from the draft
@@ -304,7 +314,7 @@ module Cms
304
314
  end
305
315
 
306
316
  def as_of_draft_version
307
- as_of_version(draft.version)
317
+ build_object_from_version(draft)
308
318
  end
309
319
 
310
320
  # Find a Content Block as of a specific version.
@@ -314,27 +324,7 @@ module Cms
314
324
  def as_of_version(version)
315
325
  v = find_version(version)
316
326
  raise ActiveRecord::RecordNotFound.new("version #{version.inspect} does not exist for <#{self.class}:#{id}>") unless v
317
- obj = self.class.new
318
-
319
- (self.class.versioned_columns + [:version, :created_at, :created_by_id, :updated_at, :updated_by_id]).each do |a|
320
- obj.send("#{a}=", v.send(a))
321
- end
322
- obj.id = id
323
- obj.lock_version = lock_version
324
-
325
- # Need to do this so associations can be loaded
326
- obj.instance_variable_set("@persisted", true)
327
- obj.instance_variable_set("@new_record", false)
328
-
329
- # Callback to allow us to load other data when an older version is loaded
330
- obj.after_as_of_version if obj.respond_to?(:after_as_of_version)
331
-
332
- # Last but not least, clear the changed attributes
333
- if changed_attrs = obj.send(:changed_attributes)
334
- changed_attrs.clear
335
- end
336
-
337
- obj
327
+ build_object_from_version(v)
338
328
  end
339
329
 
340
330
  def revert
@@ -377,6 +367,35 @@ module Cms
377
367
  return false
378
368
  end
379
369
 
370
+ private
371
+
372
+ # Given a ::Version object of a given type, create an original object from its attributes.
373
+ #
374
+ # @param [Class#name::Version] version_of_object (i.e. HtmlBlock::Version)
375
+ # @return [Class#name] i.e. HtmlBlock
376
+ def build_object_from_version(version_of_object)
377
+ obj = self.class.new
378
+
379
+ (self.class.versioned_columns + [:version, :created_at, :created_by_id, :updated_at, :updated_by_id]).each do |a|
380
+ obj.send("#{a}=", version_of_object.send(a))
381
+ end
382
+ obj.id = id
383
+ obj.lock_version = lock_version
384
+
385
+ # Need to do this so associations can be loaded
386
+ obj.instance_variable_set("@persisted", true)
387
+ obj.instance_variable_set("@new_record", false)
388
+
389
+ # Callback to allow us to load other data when an older version is loaded
390
+ obj.after_as_of_version if obj.respond_to?(:after_as_of_version)
391
+
392
+ # Last but not least, clear the changed attributes
393
+ if changed_attrs = obj.send(:changed_attributes)
394
+ changed_attrs.clear
395
+ end
396
+
397
+ obj
398
+ end
380
399
  end
381
400
  end
382
401
 
@@ -14,18 +14,18 @@ module Cms
14
14
 
15
15
  def handle_not_found_on_page(exception)
16
16
  logger.warn "Page Not Found"
17
- handle_error_with_cms_page('/system/not_found', exception, :not_found)
17
+ handle_error_with_cms_page(Cms::ErrorPages::NOT_FOUND_PATH, exception, :not_found)
18
18
  end
19
19
 
20
20
  def handle_access_denied_on_page(exception)
21
21
  logger.warn "Access Denied"
22
- handle_error_with_cms_page('/system/access_denied', exception, :forbidden)
22
+ handle_error_with_cms_page(Cms::ErrorPages::FORBIDDEN_PATH, exception, :forbidden)
23
23
  end
24
24
 
25
25
  def handle_server_error_on_page(exception)
26
26
  logger.warn "Exception: #{exception.message}\n"
27
27
  logger.warn "#{exception.backtrace.join("\n")}\n"
28
- handle_error_with_cms_page('/system/server_error', exception, :internal_server_error)
28
+ handle_error_with_cms_page(Cms::ErrorPages::SERVER_ERROR_PATH, exception, :internal_server_error)
29
29
  end
30
30
 
31
31
  private
@@ -0,0 +1,8 @@
1
+ module Cms
2
+ module ErrorPages
3
+
4
+ NOT_FOUND_PATH = '/system/not_found'
5
+ FORBIDDEN_PATH = '/system/access_denied'
6
+ SERVER_ERROR_PATH = '/system/server_error'
7
+ end
8
+ end
data/lib/cms/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  ##
2
- # Allows the precise version of BrowserCMS to be determined problematically.
2
+ # Allows the precise version of BrowserCMS to be determined programatically.
3
3
  #
4
4
  module Cms
5
- VERSION = "3.3.2"
5
+ VERSION = "3.3.3"
6
6
  end
@@ -22,6 +22,7 @@ module BrowserCms
22
22
  # Migrations/seed data
23
23
  'db/migrate/20080815014337_browsercms_3_0_0.rb',
24
24
  'db/migrate/20091109175123_browsercms_3_0_5.rb',
25
+ 'db/migrate/20100117144039_browsercms315.rb',
25
26
  'db/migrate/20100705083859_browsercms_3_3_0.rb',
26
27
  'db/seeds.rb'
27
28
  ]
@@ -671,4 +671,4 @@ into proprietary programs. If your program is a subroutine library, you
671
671
  may consider it more useful to permit linking proprietary applications with
672
672
  the library. If this is what you want to do, use the GNU Lesser General
673
673
  Public License instead of this License. But first, please read
674
- <http://www.gnu.org/philosophy/why-not-lgpl.html>.
674
+ <http://www.gnu.org/philosophy/why-not-lgpl.html>.
@@ -0,0 +1,43 @@
1
+ def create_pages(root)
2
+ (1..20).each do |i|
3
+ Page.create!(:name=>"Page #{i}", :path=>"#{root.path}/page-#{i}", :section=>root, :template_file_name=>"default.html.erb", :publish_on_save=>true)
4
+ end
5
+ end
6
+
7
+ def reset_root_user_password
8
+ u = User.find(1)
9
+ u.password= "cmsadmin"
10
+ u.password_confirmation = "cmsadmin"
11
+ u.save!
12
+
13
+ puts "Reset #{u.login}'s password to '#{u.password}'."
14
+ end
15
+
16
+ namespace :cms do
17
+
18
+ task "load" do
19
+ sh "mysql -u root browsercms_development --password= < db/backups/backup.sql"
20
+ end
21
+
22
+ task "correct" => :environment do
23
+ ActiveRecord::Base.connection.execute("UPDATE portlets SET type = 'DynamicPortlet' where type != 'DynamicPortlet'")
24
+ ct = ["'CategoryType'", "'Category'", "'HtmlBlock'", "'Portlet'", "'FileBlock'", "'ImageBlock'", "'Tag'"].join(",")
25
+ ActiveRecord::Base.connection.execute("DELETE FROM content_types where name not in (#{ct})")
26
+ reset_root_user_password
27
+ end
28
+
29
+ desc "Load a CMS site backup (a .sql file must be called db/backups/backup.sql) for testing."
30
+ task "load:backup" => ['db:drop','db:create', 'cms:load', 'cms:correct', 'db:migrate']
31
+
32
+ desc "Load some sample pages for performance tuning"
33
+ task "load:pages" => :environment do
34
+ root = Section.root.first
35
+ create_pages(root)
36
+ (21..40).each do |i|
37
+ sec = Section.create! :name=>"Section #{i}", :path=>"/section-#{i}/", :parent=>root
38
+ create_pages(sec)
39
+ end
40
+
41
+ end
42
+
43
+ end