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.
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
@@ -1,10 +1,33 @@
1
+ require 'ancestry'
2
+
1
3
  class SectionNode < ActiveRecord::Base
2
- belongs_to :section
3
- belongs_to :node, :polymorphic => :true
4
+ has_ancestry
5
+
6
+ # This is the parent section for this node
7
+ # For backwards compatiblity
8
+ def parent_section
9
+ self.parent ? self.parent.node : nil
10
+ end
11
+
12
+ alias :section :parent_section
4
13
 
5
- acts_as_list :scope => :section
14
+ # For backwards compatiblity
15
+ def section=(new_section)
16
+ self.parent = new_section.node
17
+ end
18
+
19
+ # The item this node links to
20
+ belongs_to :node, :polymorphic => :true, :inverse_of => :section_node
21
+
22
+ acts_as_list
23
+ # For acts_as_list. Specifies that position should be unique within a section.
24
+ def scope_condition
25
+ ancestry ? "ancestry = '#{ancestry}'" : 'ancestry IS NULL'
26
+ end
6
27
 
7
28
  scope :of_type, lambda{|types| {:conditions => ["section_nodes.node_type IN (?)", types]}}
29
+ scope :in_order, :order => "position asc"
30
+ scope :fetch_nodes, :include => :node
8
31
 
9
32
  def visible?
10
33
  return false unless node
@@ -27,27 +50,29 @@ class SectionNode < ActiveRecord::Base
27
50
  def page?
28
51
  node_type == 'Page'
29
52
  end
30
-
31
- def move_to(sec, pos)
53
+
54
+ # @param [Section] section
55
+ # @param [Integer] position
56
+ def move_to(section, position)
32
57
  #logger.info "Moving Section Node ##{id} to Section ##{sec.id} Position #{pos}"
33
58
  transaction do
34
- if section != sec
59
+ if self.parent != section.node
35
60
  remove_from_list
36
- self.section = sec
61
+ self.parent = section.node
37
62
  save
38
63
  end
39
64
 
40
- if pos < 0
41
- pos = 0
65
+ if position < 0
66
+ position = 0
42
67
  else
43
68
  #This helps prevent the position from getting out of whack
44
69
  #If you pass in a really high number for position,
45
70
  #this just corrects it to the right number
46
- node_count = SectionNode.count(:conditions => {:section_id => section_id})
47
- pos = node_count if pos > node_count
71
+ node_count = SectionNode.count(:conditions => {:ancestry => ancestry})
72
+ position = node_count if position > node_count
48
73
  end
49
74
 
50
- insert_at_position(pos)
75
+ insert_at_position(position)
51
76
  end
52
77
  end
53
78
 
@@ -77,17 +102,9 @@ class SectionNode < ActiveRecord::Base
77
102
  #1.0/0 == Infinity
78
103
  move_to(sec, 1.0/0)
79
104
  end
80
-
81
- def ancestors()
82
- ancestors = []
83
- fn = lambda do |sn|
84
- ancestors << sn.section
85
- if sn.section && !sn.section.root?
86
- fn.call(sn.section.node)
87
- end
88
- end
89
- fn.call(self)
90
- ancestors.reverse
105
+
106
+
107
+ def ancestry_path
108
+ path_ids.join "/"
91
109
  end
92
-
93
110
  end
@@ -50,7 +50,6 @@
50
50
  <% page_title "Content Library / List #{content_type.display_name_plural}" %>
51
51
  <% @toolbar_title = "List #{content_type.display_name_plural}" %>
52
52
  <%= render :partial => 'cms/blocks/toolbar' %>
53
-
54
53
  <div class="roundedcorners">
55
54
  <table id="blocks" class="data">
56
55
  <thead>
@@ -90,8 +89,9 @@
90
89
  col_ct += 1 if content_type.model_class.publishable? %>
91
90
  <% @blocks.each do |b| %>
92
91
  <% block = b.class.versioned? ? b.as_of_draft_version : b %>
93
- <tr id="<%= block.class.name.underscore %>_<%= block.id %>" class="<%= block.class.name.underscore %> <%= block.class.publishable? && !block.published? ? 'draft' : 'published' %> <%= 'non-editable' unless current_user.able_to_edit?(block) %> <%= 'non-publishable' unless current_user.able_to_publish?(block) %>">
94
- <td class="first"></td>
92
+
93
+ <%= block_row_tag(block) %>
94
+ <td class="first"></td>
95
95
  <% content_type.columns_for_index.each_with_index do |column, i| %>
96
96
  <td class="<%= column[:label].gsub(' ', '').underscore %>">
97
97
  <div<%= ' class="dividers"' if (i + 3 < col_ct) %>>
@@ -105,7 +105,7 @@
105
105
  </td>
106
106
  <% end %>
107
107
  <% if content_type.model_class.respond_to?(:updated_at) %><td class="updated"><div class="dividers"><%= block.updated_at.to_s(:date) %></div></td><% end %>
108
- <% if content_type.model_class.connectable? %><td class="used"><div class="dividers"><%= block.connected_pages.count %></div></td><% end %>
108
+ <% if content_type.model_class.connectable? %><td class="used"><div class="dividers"><%= block.connected_pages.size %></div></td><% end %>
109
109
  <% if content_type.model_class.publishable? %><td class="block_status"><%= status_icon(block.status) %> <div><%= block.status %></div></td><% end %>
110
110
  <td class="last"></td>
111
111
  </tr>
@@ -3,7 +3,7 @@
3
3
  root.full_path = root.name
4
4
  @sections = []
5
5
  @sections << root
6
- @sections += root.all_children_with_name
6
+ @sections += root.master_section_list
7
7
  @sections.each {|s| s.full_path = "/" + s.full_path unless s == root }
8
8
  @block.attachment_file_path = @block.attachment.file_path if @block.attachment_file_path.blank? && !@block.new_record?
9
9
  %>
@@ -3,7 +3,7 @@
3
3
  root.full_path = root.name
4
4
  @sections = []
5
5
  @sections << root
6
- @sections += root.all_children_with_name
6
+ @sections += root.master_section_list
7
7
  @sections.each {|s| s.full_path = "/" + s.full_path unless s == root }
8
8
  @block.attachment_file_path = @block.attachment.file_path if @block.attachment_file_path.blank? && !@block.new_record?
9
9
  %>
@@ -1,11 +1,14 @@
1
- <ul id="section_node_<%= section_node.id %>" class="section_node<%= " rootlet" if root %>" style="display: <%= display ? "''" : "none" %>">
1
+ <% first_level = in_first_level?(node)
2
+ %>
3
+ <%= sitemap_ul_tag(node) %>
2
4
  <li>
3
5
  <%= render :partial => "node", :locals => {
4
6
  :node => node,
5
7
  :node_type => "link",
6
- :icon => action_icon(root ? :root_link : :link),
8
+ :icon => action_icon(first_level ? :root_link : :link),
7
9
  :published_status_icon => status_icon(node.status),
8
- :published_status_label => node.published? ? "Published" : "Draft"
10
+ :published_status_label => node.published? ? "Published" : "Draft",
11
+ :parent => parent
9
12
  } %>
10
13
  </li>
11
14
  </ul>
@@ -4,13 +4,22 @@
4
4
  published_status_icon = defined?(published_status_icon) ? published_status_icon : nil
5
5
  published_status_label = defined?(published_status_label) ? published_status_label : nil
6
6
 
7
+ editable_class = ""
8
+ case node_type
9
+ when "section"
10
+ editable_class = "non-editable" unless @modifiable_sections.include?(node)
11
+ else
12
+ editable_class = "non-editable" unless defined?(parent) && @modifiable_sections.include?(parent)
13
+ end
14
+
15
+ node_type_class = node_type == "section" && node.root? ? 'root' : ''
7
16
  %>
8
17
  <div class="roundedcorners">
9
18
  <table class="section_node <%= node_type %> <%= "movable" if current_user.able_to?(:publish_content) %>" width="100%" cellspacing="0" cellpadding="0">
10
19
  <tr><td colspan="4" class="drop-before"></td></tr>
11
20
  <tr<%= ' class="doubled"' if access_icon && hidden %>>
12
- <td id="<%= node_type %>_<%= node.id %>" class="<%= node_type == "section" && node.root? ? 'root' : '' %> <%= node_type %> node <%= 'non-editable' unless current_user.able_to_edit?(node) %>">
13
- <%= raw icon %>
21
+ <td id="<%= node_type %>_<%= node.id %>" class="<%= node_type_class %> <%= node_type %> node <%= editable_class %>">
22
+ <%= icon.html_safe %>
14
23
  <div><%= h(node.name) %></div>
15
24
  </td>
16
25
  <td class="sitemap_hidden divided">
@@ -1,14 +1,20 @@
1
- <% status = node.archived? ? :archived : node.status %>
2
- <ul id="section_node_<%= section_node.id %>" class="section_node<%= " rootlet" if root %>" style="display: <%= display ? "''" : "none" %>">
1
+ <%
2
+ page = node
3
+ status_icon = page.archived? ? :archived : page.status
4
+ first_level = in_first_level?(node)
5
+
6
+ %>
7
+ <%= sitemap_ul_tag(node) %>
3
8
  <li>
4
9
  <%= render :partial => "node", :locals => {
5
10
  :node => node,
6
11
  :node_type => "page",
7
- :icon => action_icon(root ? :root_page : :page),
8
- :hidden => node.hidden?,
9
- :access_icon => status_icon(node.section ? node.section.status : ''),
10
- :published_status_icon => status_icon(status),
11
- :published_status_label => status.to_s.titleize
12
+ :icon => action_icon(first_level ? :root_page : :page),
13
+ :hidden => page.hidden?,
14
+ :access_icon => status_icon(access_icon),
15
+ :published_status_icon => status_icon(status_icon),
16
+ :published_status_label => status_icon.to_s.titleize,
17
+ :parent => parent
12
18
  } %>
13
19
  </li>
14
20
  </ul>
@@ -1,12 +1,28 @@
1
- <ul id="section_node_<%= section_node.id %>" class="section_node<%= " rootlet" if root %>" style="display: <%= display ? "''" : "none" %>">
1
+ <%
2
+ children = child_hash[key].keys
3
+ section_node = key
4
+ access_status = access_status(node, @public_sections)
5
+ first_level = in_first_level?(node)
6
+ %>
7
+ <%= sitemap_ul_tag(node) %>
2
8
  <li>
3
9
  <%= render :partial => "node", :locals => {
4
- :node => node,
5
- :node_type => "section",
6
- :icon => "#{section_icons(node)} #{action_icon(root ? :root_folder : :folder, :class => "folder")}",
7
- :hidden => node.hidden?,
8
- :access_icon => status_icon(node.status),
9
- } %>
10
- <%= render :partial => "section_node", :collection => node.child_nodes.all(:order => 'position'), :locals => {:display => false} %>
10
+ :node => node,
11
+ :node_type => "section",
12
+ :icon => "#{section_icons(section_node, children)} #{action_icon(first_level ? :root_folder : :folder, :class => "folder")}",
13
+ :hidden => node.hidden?,
14
+ :access_icon => status_icon(access_status),
15
+ :parent => parent
16
+ } %>
17
+ <% children.each do |child_section_node| %>
18
+ <%= render :partial => child_section_node.node.partial_for,
19
+ :locals => {:access_icon => access_status,
20
+ :node => child_section_node.node,
21
+ :parent => node,
22
+ :child_hash => child_hash[key],
23
+ :key => child_section_node
24
+ } %>
25
+ <% end %>
26
+
11
27
  </li>
12
28
  </ul>
@@ -20,12 +20,24 @@
20
20
  <ul id="root_<%= @section.id %>" class="root" style="padding-left: 0">
21
21
  <li>
22
22
  <%= render :partial => "node", :locals => {
23
- :node => @section,
24
- :node_type => "section",
25
- :icon => action_icon(:home),
26
- :display => true
27
- } %>
23
+ :node => @section,
24
+ :node_type => "section",
25
+ :icon => action_icon(:home),
26
+ :display => true
27
+ } %>
28
28
  </li>
29
29
  </ul>
30
- <%= render :partial => "section_node", :collection => @section.child_nodes.all(:order => 'position'), :locals => {:display => true, :root => true} %>
30
+ <%
31
+ access_status = access_status(@section, @public_sections)
32
+ @sitemap[@root_section_node].keys.each do |child_section_node| %>
33
+ <%= render :partial => child_section_node.node.partial_for,
34
+ :locals => {:access_icon => access_status,
35
+ :node => child_section_node.node,
36
+ :parent => @section,
37
+ :child_hash => @sitemap[@root_section_node],
38
+ :key => child_section_node
39
+ }
40
+ %>
41
+ <% end %>
31
42
  </div>
43
+
@@ -8,8 +8,8 @@
8
8
  <%= collection.total_entries %>
9
9
  </div>
10
10
  <div class="links">
11
- <%= link_to "&nbsp;", first_page_path, :id => "first_page_link" %>
12
- <%= link_to "&nbsp;", previous_page_path, :id => "previous_page_link" %>
11
+ <%= link_to "&nbsp;".html_safe, first_page_path, :id => "first_page_link" %>
12
+ <%= link_to "&nbsp;".html_safe, previous_page_path, :id => "previous_page_link" %>
13
13
  <span>
14
14
  <% url = URI.parse(current_page_path) %>
15
15
  <%= form_tag url.path, :method => :get, :class => "current_page" do %>
@@ -24,8 +24,8 @@
24
24
  </strong>
25
25
  <% end %>
26
26
  </span>
27
- <%= link_to "&nbsp;", next_page_path, :id => "next_page_link" %>
28
- <%= link_to "&nbsp;", last_page_path, :id => "last_page_link" %>
27
+ <%= link_to "&nbsp;".html_safe, next_page_path, :id => "next_page_link" %>
28
+ <%= link_to "&nbsp;".html_safe, last_page_path, :id => "last_page_link" %>
29
29
  </div>
30
30
  <br clear="all"/>
31
31
  </div>
@@ -1,5 +1,3 @@
1
- <%= error_message_on :user, :password %>
2
-
3
1
  <% if flash_scope = flash[:reset_password] -%>
4
2
  <% if flash_scope[:error] -%>
5
3
  <span class="reset-password-error"><%= flash_scope[:error] %></span>
data/browsercms.gemspec CHANGED
@@ -1,5 +1,3 @@
1
- # This file is now managed directly, rather than generated by Jeweler.
2
- #
3
1
  require File.dirname(__FILE__) + "/lib/cms/version.rb"
4
2
 
5
3
  Gem::Specification.new do |s|
@@ -7,9 +5,7 @@ Gem::Specification.new do |s|
7
5
  s.name = %q{browsercms}
8
6
  s.version = Cms::VERSION
9
7
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
8
  s.authors = ["BrowserMedia"]
12
- s.date = %q{2011-03-15}
13
9
  s.summary = %q{BrowserCMS is a a general purpose, open source Web Content Management System (CMS), written using Ruby on Rails.}
14
10
  s.description = %q{Web Content Management in Rails.}
15
11
  s.email = %q{github@browsermedia.com}
@@ -42,6 +38,7 @@ Gem::Specification.new do |s|
42
38
  s.files -= Dir['test/dummy/*']
43
39
 
44
40
  s.add_dependency('rails', "~> 3.0.7")
41
+ s.add_dependency "ancestry", "~> 1.2.4"
45
42
 
46
43
  # Required only for bcms-upgrade
47
44
  s.add_dependency('term-ansicolor')
@@ -0,0 +1,94 @@
1
+ class Browsercms315 < ActiveRecord::Migration
2
+ def self.up
3
+ generate_ancestry_from_section_id
4
+ update_latest_version_cache
5
+
6
+ INDEXES.each do |index|
7
+ add_index *index
8
+ end
9
+ end
10
+
11
+ def self.down
12
+ # This migration is not reversible since it removes the original section_id column.
13
+ end
14
+
15
+ # Add some very commonly used indexes to improve the site performance as the # of pages/content grows (i.e. several thousand pages)
16
+ INDEXES = [
17
+ [:pages, :deleted],
18
+ [:pages, :path],
19
+ [:pages, :version],
20
+ [:page_versions, :page_id],
21
+ [:groups, :code],
22
+ [:groups, :group_type_id],
23
+ [:group_types, :cms_access],
24
+ [:group_sections, :section_id],
25
+ [:group_sections, :group_id],
26
+ [:users, :expires_at],
27
+ [:user_group_memberships, :group_id],
28
+ [:user_group_memberships, :user_id],
29
+ [:group_permissions, :group_id],
30
+ [:group_permissions, :permission_id],
31
+ [:group_permissions, [:group_id, :permission_id]],
32
+ [:section_nodes, :node_type],
33
+ [:section_nodes, :ancestry],
34
+ [:connectors, :page_id],
35
+ [:connectors, :page_version],
36
+ [:html_blocks, :deleted],
37
+ [:html_block_versions, :html_block_id],
38
+ [:html_block_versions, :version],
39
+ [:portlet_attributes, :portlet_id],
40
+ [:portlets, :name],
41
+ [:sections, :path],
42
+ [:redirects, :from_path],
43
+ [:connectors, :connectable_version],
44
+ [:connectors, :connectable_type],
45
+ [:content_types, :content_type_group_id],
46
+ [:content_types, :name],
47
+ [:file_block_versions, :file_block_id],
48
+ [:file_block_versions, :version],
49
+ [:file_blocks, :deleted],
50
+ [:file_blocks, :type],
51
+ [:attachment_versions, :attachment_id],
52
+ [:tasks, :page_id],
53
+ [:tasks, :completed_at],
54
+ [:tasks, :assigned_to_id],
55
+ ]
56
+
57
+ private
58
+
59
+ # v3.1.5 uses Ancestry to manage the parent child relationship between sections and their children.
60
+ # This converts the data from the old section_id to use the ancestry column.
61
+ def self.generate_ancestry_from_section_id
62
+ add_column :section_nodes, :ancestry, :string
63
+ add_column :section_nodes, :temp_parent_id, :integer
64
+
65
+ SectionNode.reset_column_information
66
+ root_section = Section.root.first
67
+ SectionNode.create!(:node => root_section) if root_section
68
+
69
+ all_nodes_but_root = SectionNode.find(:all, :conditions=>["section_id IS NOT NULL"])
70
+ all_nodes_but_root.each do |sn|
71
+ parent_node = SectionNode.find(:first, :conditions => ["node_id = ? and node_type = 'Section'", sn.section_id])
72
+ sn.temp_parent_id = parent_node.id
73
+ sn.save!
74
+ end
75
+ rename_column :section_nodes, :temp_parent_id, :parent_id # Ancestry works off the 'parent_id' column.
76
+
77
+ SectionNode.build_ancestry_from_parent_ids!
78
+ remove_column :section_nodes, :section_id
79
+ remove_column :section_nodes, :parent_id
80
+ SectionNode.reset_column_information
81
+ end
82
+
83
+ # Adds a 'latest_version' pointer to pages and links. Greatly reduces the number of queries the sitemap requires to determine if pages are in draft/published mode
84
+ def self.update_latest_version_cache
85
+ add_column :pages, :latest_version, :integer
86
+ add_column :links, :latest_version, :integer
87
+ Page.all.each do |p|
88
+ p.update_latest_version
89
+ end
90
+ Link.all.each do |link|
91
+ link.update_latest_version
92
+ end
93
+ end
94
+ end
data/lib/acts_as_list.rb CHANGED
@@ -7,7 +7,7 @@ module ActsAsList
7
7
  # The class that has this specified needs to have a +position+ column defined as an integer on
8
8
  # the mapped database table.
9
9
  #
10
- # Todo list example:
10
+ # To Do list example:
11
11
  #
12
12
  # class TodoList < ActiveRecord::Base
13
13
  # has_many :todo_items, :order => "position"