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
@@ -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"