browsercms 3.3.2 → 3.3.3
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.
- data/app/controllers/cms/content_block_controller.rb +2 -2
- data/app/controllers/cms/content_controller.rb +1 -1
- data/app/controllers/cms/section_nodes_controller.rb +6 -1
- data/app/controllers/cms/sections_controller.rb +1 -1
- data/app/helpers/cms/application_helper.rb +1 -1
- data/app/helpers/cms/content_block_helper.rb +27 -0
- data/app/helpers/cms/section_nodes_helper.rb +43 -5
- data/app/models/abstract_file_block.rb +17 -2
- data/app/models/attachment.rb +16 -34
- data/app/models/file_block.rb +0 -12
- data/app/models/image_block.rb +0 -12
- data/app/models/link.rb +4 -21
- data/app/models/page.rb +36 -35
- data/app/models/section.rb +82 -42
- data/app/models/section_node.rb +41 -24
- data/app/views/cms/blocks/index.html.erb +4 -4
- data/app/views/cms/file_blocks/_form.html.erb +1 -1
- data/app/views/cms/image_blocks/_form.html.erb +1 -1
- data/app/views/cms/section_nodes/_link.html.erb +6 -3
- data/app/views/cms/section_nodes/_node.html.erb +11 -2
- data/app/views/cms/section_nodes/_page.html.erb +13 -7
- data/app/views/cms/section_nodes/_section.html.erb +24 -8
- data/app/views/cms/section_nodes/index.html.erb +18 -6
- data/app/views/cms/shared/_pagination.html.erb +4 -4
- data/app/views/portlets/reset_password/render.html.erb +0 -2
- data/browsercms.gemspec +1 -4
- data/db/migrate/20100117144039_browsercms315.rb +94 -0
- data/lib/acts_as_list.rb +1 -1
- data/lib/browsercms.rb +3 -1
- data/lib/cms/addressable.rb +83 -0
- data/lib/cms/behaviors/attaching.rb +42 -24
- data/lib/cms/behaviors/connecting.rb +2 -1
- data/lib/cms/behaviors/publishing.rb +12 -3
- data/lib/cms/behaviors/versioning.rb +43 -24
- data/lib/cms/content_rendering_support.rb +3 -3
- data/lib/cms/error_pages.rb +8 -0
- data/lib/cms/version.rb +2 -2
- data/lib/generators/browser_cms/cms/cms_generator.rb +1 -0
- data/lib/generators/cms/upgrade_module/templates/GPL.txt +1 -1
- data/lib/tasks/data.rake +43 -0
- metadata +27 -8
- 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 = [
|
5
|
-
|
4
|
+
SANITIZATION_REGEXES = [[/\s/, '_'], [/[&+()]/, '-'], [/[=?!'"{}\[\]#<>%]/, '']]
|
5
|
+
|
6
6
|
def self.included(model_class)
|
7
7
|
model_class.extend(MacroMethods)
|
8
8
|
end
|
9
|
-
|
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
|
-
|
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
|
-
|
108
|
-
|
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
|
-
#
|
123
|
-
def
|
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
|
-
|
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
|
@@ -125,15 +125,24 @@ module Cms
|
|
125
125
|
end
|
126
126
|
|
127
127
|
def status
|
128
|
-
|
129
|
-
|
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?
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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(
|
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(
|
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(
|
28
|
+
handle_error_with_cms_page(Cms::ErrorPages::SERVER_ERROR_PATH, exception, :internal_server_error)
|
29
29
|
end
|
30
30
|
|
31
31
|
private
|
data/lib/cms/version.rb
CHANGED
@@ -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>.
|
data/lib/tasks/data.rake
ADDED
@@ -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
|