Merge branch 'master' into plugin-hooks

Conflicts:

	lib/redmine/plugin.rb
This commit is contained in:
Eric Davis
2008-07-28 16:14:10 -07:00
79 changed files with 702 additions and 219 deletions
+11 -14
View File
@@ -15,6 +15,8 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'uri'
class ApplicationController < ActionController::Base
before_filter :user_setup, :check_if_login_required, :set_localization
filter_parameter_logging :password
@@ -77,8 +79,7 @@ class ApplicationController < ActionController::Base
def require_login
if !User.current.logged?
store_location
redirect_to :controller => "account", :action => "login"
redirect_to :controller => "account", :action => "login", :back_url => request.request_uri
return false
end
true
@@ -115,20 +116,16 @@ class ApplicationController < ActionController::Base
end
end
# store current uri in session.
# return to this location by calling redirect_back_or_default
def store_location
session[:return_to_params] = params
end
# move to the last store_location call or to the passed default one
def redirect_back_or_default(default)
if session[:return_to_params].nil?
redirect_to default
else
redirect_to session[:return_to_params]
session[:return_to_params] = nil
back_url = params[:back_url]
if !back_url.blank?
uri = URI.parse(back_url)
# do not redirect user to another host
if uri.relative? || (uri.host == request.host)
redirect_to(back_url) and return
end
end
redirect_to default
end
def render_403
+10 -82
View File
@@ -226,94 +226,22 @@ class ProjectsController < ApplicationController
@date_to ||= Date.today + 1
@date_from = @date_to - @days
@with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
@event_types = %w(issues news files documents changesets wiki_pages messages)
if @project
@event_types.delete('wiki_pages') unless @project.wiki
@event_types.delete('changesets') unless @project.repository
@event_types.delete('messages') unless @project.boards.any?
# only show what the user is allowed to view
@event_types = @event_types.select {|o| User.current.allowed_to?("view_#{o}".to_sym, @project)}
@with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
end
@scope = @event_types.select {|t| params["show_#{t}"]}
# default events if none is specified in parameters
@scope = (@event_types - %w(wiki_pages messages))if @scope.empty?
@events = []
if @scope.include?('issues')
cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_issues, :project => @project, :with_subprojects => @with_subprojects))
cond.add(["#{Issue.table_name}.created_on BETWEEN ? AND ?", @date_from, @date_to])
@events += Issue.find(:all, :include => [:project, :author, :tracker], :conditions => cond.conditions)
cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_issues, :project => @project, :with_subprojects => @with_subprojects))
cond.add(["#{Journal.table_name}.journalized_type = 'Issue' AND #{Journal.table_name}.created_on BETWEEN ? AND ?", @date_from, @date_to])
cond.add("#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> ''")
@events += Journal.find(:all, :include => [{:issue => :project}, :details, :user], :conditions => cond.conditions)
end
if @scope.include?('news')
cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_news, :project => @project, :with_subprojects => @with_subprojects))
cond.add(["#{News.table_name}.created_on BETWEEN ? AND ?", @date_from, @date_to])
@events += News.find(:all, :include => [:project, :author], :conditions => cond.conditions)
end
if @scope.include?('files')
cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_files, :project => @project, :with_subprojects => @with_subprojects))
cond.add(["#{Attachment.table_name}.created_on BETWEEN ? AND ?", @date_from, @date_to])
@events += Attachment.find(:all, :select => "#{Attachment.table_name}.*",
:joins => "LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " +
"LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id",
:conditions => cond.conditions)
end
if @scope.include?('documents')
cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_documents, :project => @project, :with_subprojects => @with_subprojects))
cond.add(["#{Document.table_name}.created_on BETWEEN ? AND ?", @date_from, @date_to])
@events += Document.find(:all, :include => :project, :conditions => cond.conditions)
cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_documents, :project => @project, :with_subprojects => @with_subprojects))
cond.add(["#{Attachment.table_name}.created_on BETWEEN ? AND ?", @date_from, @date_to])
@events += Attachment.find(:all, :select => "#{Attachment.table_name}.*",
:joins => "LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " +
"LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id",
:conditions => cond.conditions)
end
if @scope.include?('wiki_pages')
select = "#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comments, " +
"#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title, " +
"#{WikiContent.versioned_table_name}.page_id, #{WikiContent.versioned_table_name}.author_id, " +
"#{WikiContent.versioned_table_name}.id"
joins = "LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " +
"LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " +
"LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id"
@activity = Redmine::Activity::Fetcher.new(User.current, :project => @project, :with_subprojects => @with_subprojects)
@activity.scope_select {|t| !params["show_#{t}"].nil?}
@activity.default_scope! if @activity.scope.empty?
cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_wiki_pages, :project => @project, :with_subprojects => @with_subprojects))
cond.add(["#{WikiContent.versioned_table_name}.updated_on BETWEEN ? AND ?", @date_from, @date_to])
@events += WikiContent.versioned_class.find(:all, :select => select, :joins => joins, :conditions => cond.conditions)
end
if @scope.include?('changesets')
cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_changesets, :project => @project, :with_subprojects => @with_subprojects))
cond.add(["#{Changeset.table_name}.committed_on BETWEEN ? AND ?", @date_from, @date_to])
@events += Changeset.find(:all, :include => {:repository => :project}, :conditions => cond.conditions)
end
if @scope.include?('messages')
cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_messages, :project => @project, :with_subprojects => @with_subprojects))
cond.add(["#{Message.table_name}.created_on BETWEEN ? AND ?", @date_from, @date_to])
@events += Message.find(:all, :include => [{:board => :project}, :author], :conditions => cond.conditions)
end
@events_by_day = @events.group_by(&:event_date)
events = @activity.events(@date_from, @date_to)
respond_to do |format|
format.html { render :layout => false if request.xhr? }
format.html {
@events_by_day = events.group_by(&:event_date)
render :layout => false if request.xhr?
}
format.atom {
title = (@scope.size == 1) ? l("label_#{@scope.first.singularize}_plural") : l(:label_activity)
render_feed(@events, :title => "#{@project || Setting.app_title}: #{title}")
render_feed(events, :title => "#{@project || Setting.app_title}: #{title}")
}
end
end
+5 -1
View File
@@ -147,6 +147,7 @@ class WikiController < ApplicationController
:joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id",
:order => 'title'
@pages_by_date = @pages.group_by {|p| p.updated_on.to_date}
@pages_by_parent_id = @pages.group_by(&:parent_id)
# export wiki to a single html file
when 'export'
@pages = @wiki.pages.find :all, :order => 'title'
@@ -164,7 +165,10 @@ class WikiController < ApplicationController
page = @wiki.find_page(params[:page])
# page is nil when previewing a new page
return render_403 unless page.nil? || editable?(page)
@attachements = page.attachments if page
if page
@attachements = page.attachments
@previewed = page.content
end
@text = params[:content][:text]
render :partial => 'common/preview'
end
+14 -7
View File
@@ -177,7 +177,8 @@ module ApplicationHelper
end
def breadcrumb(*args)
content_tag('p', args.join(' &#187; ') + ' &#187; ', :class => 'breadcrumb')
elements = args.flatten
elements.any? ? content_tag('p', args.join(' &#187; ') + ' &#187; ', :class => 'breadcrumb') : nil
end
def html_title(*args)
@@ -205,7 +206,7 @@ module ApplicationHelper
options = args.last.is_a?(Hash) ? args.pop : {}
case args.size
when 1
obj = nil
obj = options[:object]
text = args.shift
when 2
obj = args.shift
@@ -245,12 +246,12 @@ module ApplicationHelper
case options[:wiki_links]
when :local
# used for local links to html files
format_wiki_link = Proc.new {|project, title| "#{title}.html" }
format_wiki_link = Proc.new {|project, title, anchor| "#{title}.html" }
when :anchor
# used for single-file wiki export
format_wiki_link = Proc.new {|project, title| "##{title}" }
format_wiki_link = Proc.new {|project, title, anchor| "##{title}" }
else
format_wiki_link = Proc.new {|project, title| url_for(:only_path => only_path, :controller => 'wiki', :action => 'index', :id => project, :page => title) }
format_wiki_link = Proc.new {|project, title, anchor| url_for(:only_path => only_path, :controller => 'wiki', :action => 'index', :id => project, :page => title, :anchor => anchor) }
end
project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
@@ -276,9 +277,14 @@ module ApplicationHelper
end
if link_project && link_project.wiki
# extract anchor
anchor = nil
if page =~ /^(.+?)\#(.+)$/
page, anchor = $1, $2
end
# check if page exists
wiki_page = link_project.wiki.find_page(page)
link_to((title || page), format_wiki_link.call(link_project, Wiki.titleize(page)),
link_to((title || page), format_wiki_link.call(link_project, Wiki.titleize(page), anchor),
:class => ('wiki-page' + (wiki_page ? '' : ' new')))
else
# project or wiki doesn't exist
@@ -451,7 +457,8 @@ module ApplicationHelper
end
def back_url_hidden_field_tag
hidden_field_tag 'back_url', (params[:back_url] || request.env['HTTP_REFERER'])
back_url = params[:back_url] || request.env['HTTP_REFERER']
hidden_field_tag('back_url', back_url) unless back_url.blank?
end
def check_all_links(form_name)
+2 -1
View File
@@ -18,7 +18,8 @@
module SearchHelper
def highlight_tokens(text, tokens)
return text unless text && tokens && !tokens.empty?
regexp = Regexp.new "(#{tokens.join('|')})", Regexp::IGNORECASE
re_tokens = tokens.collect {|t| Regexp.escape(t)}
regexp = Regexp.new "(#{re_tokens.join('|')})", Regexp::IGNORECASE
result = ''
text.split(regexp).each_with_index do |words, i|
if result.length > 1200
+16
View File
@@ -17,6 +17,22 @@
module WikiHelper
def render_page_hierarchy(pages, node=nil)
content = ''
if pages[node]
content << "<ul class=\"pages-hierarchy\">\n"
pages[node].each do |page|
content << "<li>"
content << link_to(h(page.pretty_title), {:action => 'index', :page => page.title},
:title => (page.respond_to?(:updated_on) ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
content << "\n" + render_page_hierarchy(pages, page.id) if pages[page.id]
content << "</li>\n"
end
content << "</ul>\n"
end
content
end
def html_diff(wdiff)
words = wdiff.words.collect{|word| h(word)}
words_add = 0
+12
View File
@@ -28,6 +28,18 @@ class Attachment < ActiveRecord::Base
acts_as_event :title => :filename,
:url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}}
acts_as_activity_provider :type => 'files',
:permission => :view_files,
:find_options => {:select => "#{Attachment.table_name}.*",
:joins => "LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " +
"LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id"}
acts_as_activity_provider :type => 'documents',
:permission => :view_documents,
:find_options => {:select => "#{Attachment.table_name}.*",
:joins => "LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " +
"LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"}
cattr_accessor :storage_path
@@storage_path = "#{RAILS_ROOT}/files"
+3
View File
@@ -30,6 +30,9 @@ class Changeset < ActiveRecord::Base
:include => {:repository => :project},
:project_key => "#{Repository.table_name}.project_id",
:date_column => 'committed_on'
acts_as_activity_provider :timestamp => "#{table_name}.committed_on",
:find_options => {:include => {:repository => :project}}
validates_presence_of :repository_id, :revision, :committed_on, :commit_date
validates_uniqueness_of :revision, :scope => :repository_id
+2 -1
View File
@@ -24,7 +24,8 @@ class Document < ActiveRecord::Base
acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"},
:author => Proc.new {|o| (a = o.attachments.find(:first, :order => "#{Attachment.table_name}.created_on ASC")) ? a.author : nil },
:url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}}
acts_as_activity_provider :find_options => {:include => :project}
validates_presence_of :project, :title, :category
validates_length_of :title, :maximum => 60
end
+5 -1
View File
@@ -42,6 +42,8 @@ class Issue < ActiveRecord::Base
acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id}: #{o.subject}"},
:url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}}
acts_as_activity_provider :find_options => {:include => [:project, :author, :tracker]}
validates_presence_of :subject, :description, :priority, :project, :tracker, :author, :status
validates_length_of :subject, :maximum => 255
validates_inclusion_of :done_ratio, :in => 0..100
@@ -77,7 +79,9 @@ class Issue < ActiveRecord::Base
self.relations_to.clear
end
# issue is moved to another project
self.category = nil
# reassign to the category with same name if any
new_category = category.nil? ? nil : new_project.issue_categories.find_by_name(category.name)
self.category = new_category
self.fixed_version = nil
self.project = new_project
end
+6
View File
@@ -31,6 +31,12 @@ class Journal < ActiveRecord::Base
:type => Proc.new {|o| (s = o.new_status) ? (s.is_closed? ? 'issue-closed' : 'issue-edit') : 'issue-note' },
:url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.issue.id, :anchor => "change-#{o.id}"}}
acts_as_activity_provider :type => 'issues',
:permission => :view_issues,
:find_options => {:include => [{:issue => :project}, :details, :user],
:conditions => "#{Journal.table_name}.journalized_type = 'Issue' AND" +
" (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')"}
def save
# Do not save an empty journal
(details.empty? && notes.blank?) ? false : super
+3 -1
View File
@@ -31,7 +31,9 @@ class Message < ActiveRecord::Base
:type => Proc.new {|o| o.parent_id.nil? ? 'message' : 'reply'},
:url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id}.merge(o.parent_id.nil? ? {:id => o.id} :
{:id => o.parent_id, :anchor => "message-#{o.id}"})}
acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]}
attr_protected :locked, :sticky
validates_presence_of :subject, :content
validates_length_of :subject, :maximum => 255
+2 -1
View File
@@ -26,7 +26,8 @@ class News < ActiveRecord::Base
acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project
acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}}
acts_as_activity_provider :find_options => {:include => [:project, :author]}
# returns latest news for projects visible by user
def self.latest(user=nil, count=5)
find(:all, :limit => count, :conditions => Project.visible_by(user), :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
+3 -2
View File
@@ -88,7 +88,7 @@ class Query < ActiveRecord::Base
:date_past => [ ">t-", "<t-", "t-", "t", "w" ],
:string => [ "=", "~", "!", "!~" ],
:text => [ "~", "!~" ],
:integer => [ "=", ">=", "<=" ] }
:integer => [ "=", ">=", "<=", "!*", "*" ] }
cattr_reader :operators_by_filter_type
@@ -152,7 +152,8 @@ class Query < ActiveRecord::Base
"updated_on" => { :type => :date_past, :order => 10 },
"start_date" => { :type => :date, :order => 11 },
"due_date" => { :type => :date, :order => 12 },
"done_ratio" => { :type => :integer, :order => 13 }}
"estimated_hours" => { :type => :integer, :order => 13 },
"done_ratio" => { :type => :integer, :order => 14 }}
user_values = []
user_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged?
+11
View File
@@ -35,6 +35,17 @@ class WikiContent < ActiveRecord::Base
:type => 'wiki-page',
:url => Proc.new {|o| {:controller => 'wiki', :id => o.page.wiki.project_id, :page => o.page.title, :version => o.version}}
acts_as_activity_provider :type => 'wiki_pages',
:timestamp => "#{WikiContent.versioned_table_name}.updated_on",
:permission => :view_wiki_pages,
:find_options => {:select => "#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comments, " +
"#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title, " +
"#{WikiContent.versioned_table_name}.page_id, #{WikiContent.versioned_table_name}.author_id, " +
"#{WikiContent.versioned_table_name}.id",
:joins => "LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " +
"LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " +
"LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id"}
def text=(plain)
case Setting.wiki_compression
when 'gzip'
+20 -1
View File
@@ -22,7 +22,8 @@ class WikiPage < ActiveRecord::Base
belongs_to :wiki
has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy
has_many :attachments, :as => :container, :dependent => :destroy
acts_as_tree :order => 'title'
acts_as_event :title => Proc.new {|o| "#{l(:label_wiki)}: #{o.title}"},
:description => :text,
:datetime => :created_on,
@@ -110,6 +111,24 @@ class WikiPage < ActiveRecord::Base
def editable_by?(usr)
!protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project)
end
def parent_title
@parent_title || (self.parent && self.parent.pretty_title)
end
def parent_title=(t)
@parent_title = t
parent_page = t.blank? ? nil : self.wiki.find_page(t)
self.parent = parent_page
end
protected
def validate
errors.add(:parent_title, :activerecord_error_invalid) if !@parent_title.blank? && parent.nil?
errors.add(:parent_title, :activerecord_error_circular_dependency) if parent && (parent == self || parent.ancestors.include?(self))
errors.add(:parent_title, :activerecord_error_not_same_project) if parent && (parent.wiki_id != wiki_id)
end
end
class WikiDiff
+1
View File
@@ -1,5 +1,6 @@
<div id="login-form">
<% form_tag({:action=> "login"}) do %>
<%= back_url_hidden_field_tag %>
<table>
<tr>
<td align="right"><label for="username"><%=l(:field_login)%>:</label></td>
+1 -1
View File
@@ -1,3 +1,3 @@
<fieldset class="preview"><legend><%= l(:label_preview) %></legend>
<%= textilizable @text, :attachments => @attachements %>
<%= textilizable @text, :attachments => @attachements, :object => @previewed %>
</fieldset>
+13
View File
@@ -44,6 +44,19 @@
:selected => @issue.assigned_to.nil?, :disabled => !@can[:update] %></li>
</ul>
</li>
<% unless @project.issue_categories.empty? -%>
<li class="folder">
<a href="#" class="submenu"><%= l(:field_category) %></a>
<ul>
<% @project.issue_categories.each do |u| -%>
<li><%= context_menu_link u.name, {:controller => 'issues', :action => 'edit', :id => @issue, 'issue[category_id]' => u, :back_to => @back}, :method => :post,
:selected => (u == @issue.category), :disabled => !@can[:update] %></li>
<% end -%>
<li><%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'edit', :id => @issue, 'issue[category_id]' => '', :back_to => @back}, :method => :post,
:selected => @issue.category.nil?, :disabled => !@can[:update] %></li>
</ul>
</li>
<% end -%>
<li class="folder">
<a href="#" class="submenu"><%= l(:field_done_ratio) %></a>
<ul>
+2 -2
View File
@@ -44,8 +44,8 @@
<% content_for :sidebar do %>
<% form_tag({}, :method => :get) do %>
<h3><%= l(:label_activity) %></h3>
<p><% @event_types.each do |t| %>
<label><%= check_box_tag "show_#{t}", 1, @scope.include?(t) %> <%= l("label_#{t.singularize}_plural")%></label><br />
<p><% @activity.event_types.each do |t| %>
<label><%= check_box_tag "show_#{t}", 1, @activity.scope.include?(t) %> <%= l("label_#{t.singularize}_plural")%></label><br />
<% end %></p>
<% if @project && @project.active_children.any? %>
<p><label><%= check_box_tag 'with_subprojects', 1, @with_subprojects %> <%=l(:label_subproject_plural)%></label></p>
+2 -1
View File
@@ -4,8 +4,9 @@
<% labelled_tabular_form_for :wiki_page, @page, :url => { :action => 'rename' } do |f| %>
<div class="box">
<p><%= f.text_field :title, :required => true, :size => 255 %></p>
<p><%= f.text_field :title, :required => true, :size => 100 %></p>
<p><%= f.check_box :redirect_existing_links %></p>
<p><%= f.text_field :parent_title, :size => 100 %></p>
</div>
<%= submit_tag l(:button_rename) %>
<% end %>
+2
View File
@@ -10,6 +10,8 @@
<%= link_to(l(:label_history), {:action => 'history', :page => @page.title}, :class => 'icon icon-history') %>
</div>
<%= breadcrumb(@page.ancestors.reverse.collect {|parent| link_to h(parent.pretty_title), {:page => parent.title}}) %>
<% if @content.version != @page.content.version %>
<p>
<%= link_to(('&#171; ' + l(:label_previous)), :action => 'index', :page => @page.title, :version => (@content.version - 1)) + " - " if @content.version > 1 %>
+1 -5
View File
@@ -4,11 +4,7 @@
<p class="nodata"><%= l(:label_no_data) %></p>
<% end %>
<ul><% @pages.each do |page| %>
<li><%= link_to page.pretty_title, {:action => 'index', :page => page.title},
:title => l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) %>
</li>
<% end %></ul>
<%= render_page_hierarchy(@pages_by_parent_id) %>
<% content_for :sidebar do %>
<%= render :partial => 'sidebar' %>