Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e613c6c10 | ||
|
|
76bcbce2ef | ||
|
|
7da7e853a3 | ||
|
|
6ae66f4dbf | ||
|
|
a98d4de1e3 | ||
|
|
5e4d66ad50 | ||
|
|
982d6bc748 | ||
|
|
3169291039 | ||
|
|
de86f4b965 |
@@ -28,7 +28,7 @@ class AdminController < ApplicationController
|
||||
|
||||
def projects
|
||||
sort_init 'name', 'asc'
|
||||
sort_update
|
||||
sort_update %w(name is_public created_on)
|
||||
|
||||
@status = params[:status] ? params[:status].to_i : 0
|
||||
conditions = nil
|
||||
|
||||
@@ -36,12 +36,13 @@ class BoardsController < ApplicationController
|
||||
end
|
||||
|
||||
def show
|
||||
sort_init "#{Message.table_name}.updated_on", "desc"
|
||||
sort_update
|
||||
sort_init 'updated_on', 'desc'
|
||||
sort_update 'created_on' => "#{Message.table_name}.created_on",
|
||||
'updated_on' => "#{Message.table_name}.updated_on"
|
||||
|
||||
@topic_count = @board.topics.count
|
||||
@topic_pages = Paginator.new self, @topic_count, per_page_option, params['page']
|
||||
@topics = @board.topics.find :all, :order => "#{Message.table_name}.sticky DESC, #{sort_clause}",
|
||||
@topics = @board.topics.find :all, :order => ["#{Message.table_name}.sticky DESC", sort_clause].compact.join(', '),
|
||||
:include => [:author, {:last_reply => :author}],
|
||||
:limit => @topic_pages.items_per_page,
|
||||
:offset => @topic_pages.current.offset
|
||||
|
||||
@@ -45,9 +45,10 @@ class IssuesController < ApplicationController
|
||||
include IssuesHelper
|
||||
|
||||
def index
|
||||
sort_init "#{Issue.table_name}.id", "desc"
|
||||
sort_update
|
||||
retrieve_query
|
||||
sort_init 'id', 'desc'
|
||||
sort_update({'id' => "#{Issue.table_name}.id"}.merge(@query.columns.inject({}) {|h, c| h[c.name.to_s] = c.sortable; h}))
|
||||
|
||||
if @query.valid?
|
||||
limit = per_page_option
|
||||
respond_to do |format|
|
||||
@@ -78,9 +79,10 @@ class IssuesController < ApplicationController
|
||||
end
|
||||
|
||||
def changes
|
||||
sort_init "#{Issue.table_name}.id", "desc"
|
||||
sort_update
|
||||
retrieve_query
|
||||
sort_init 'id', 'desc'
|
||||
sort_update({'id' => "#{Issue.table_name}.id"}.merge(@query.columns.inject({}) {|h, c| h[c.name.to_s] = c.sortable; h}))
|
||||
|
||||
if @query.valid?
|
||||
@journals = Journal.find :all, :include => [ :details, :user, {:issue => [:project, :author, :tracker, :status]} ],
|
||||
:conditions => @query.statement,
|
||||
|
||||
@@ -204,8 +204,12 @@ class ProjectsController < ApplicationController
|
||||
end
|
||||
|
||||
def list_files
|
||||
sort_init "#{Attachment.table_name}.filename", "asc"
|
||||
sort_update
|
||||
sort_init 'filename', 'asc'
|
||||
sort_update 'filename' => "#{Attachment.table_name}.filename",
|
||||
'created_on' => "#{Attachment.table_name}.created_on",
|
||||
'size' => "#{Attachment.table_name}.filesize",
|
||||
'downloads' => "#{Attachment.table_name}.downloads"
|
||||
|
||||
@versions = @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse
|
||||
render :layout => !request.xhr?
|
||||
end
|
||||
|
||||
@@ -129,7 +129,12 @@ class TimelogController < ApplicationController
|
||||
|
||||
def details
|
||||
sort_init 'spent_on', 'desc'
|
||||
sort_update
|
||||
sort_update 'spent_on' => 'spent_on',
|
||||
'user' => 'user_id',
|
||||
'activity' => 'activity_id',
|
||||
'project' => "#{Project.table_name}.name",
|
||||
'issue' => 'issue_id',
|
||||
'hours' => 'hours'
|
||||
|
||||
cond = ARCondition.new
|
||||
cond << (@issue.nil? ? @project.project_condition(Setting.display_subprojects_issues?) :
|
||||
|
||||
@@ -31,7 +31,7 @@ class UsersController < ApplicationController
|
||||
|
||||
def list
|
||||
sort_init 'login', 'asc'
|
||||
sort_update
|
||||
sort_update %w(login firstname lastname mail admin created_on last_login_on)
|
||||
|
||||
@status = params[:status] ? params[:status].to_i : 1
|
||||
conditions = "status <> 0"
|
||||
|
||||
@@ -22,8 +22,8 @@ module QueriesHelper
|
||||
end
|
||||
|
||||
def column_header(column)
|
||||
column.sortable ? sort_header_tag(column.sortable, :caption => column.caption,
|
||||
:default_order => column.default_order) :
|
||||
column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,
|
||||
:default_order => column.default_order) :
|
||||
content_tag('th', column.caption)
|
||||
end
|
||||
|
||||
|
||||
@@ -67,23 +67,31 @@ module SortHelper
|
||||
|
||||
# Updates the sort state. Call this in the controller prior to calling
|
||||
# sort_clause.
|
||||
#
|
||||
def sort_update()
|
||||
if params[:sort_key]
|
||||
sort = {:key => params[:sort_key], :order => params[:sort_order]}
|
||||
# sort_keys can be either an array or a hash of allowed keys
|
||||
def sort_update(sort_keys)
|
||||
sort_key = params[:sort_key]
|
||||
sort_key = nil unless (sort_keys.is_a?(Array) ? sort_keys.include?(sort_key) : sort_keys[sort_key])
|
||||
|
||||
sort_order = (params[:sort_order] == 'desc' ? 'DESC' : 'ASC')
|
||||
|
||||
if sort_key
|
||||
sort = {:key => sort_key, :order => sort_order}
|
||||
elsif session[@sort_name]
|
||||
sort = session[@sort_name] # Previous sort.
|
||||
else
|
||||
sort = @sort_default
|
||||
end
|
||||
session[@sort_name] = sort
|
||||
|
||||
sort_column = (sort_keys.is_a?(Hash) ? sort_keys[sort[:key]] : sort[:key])
|
||||
@sort_clause = (sort_column.blank? ? nil : "#{sort_column} #{sort[:order]}")
|
||||
end
|
||||
|
||||
# Returns an SQL sort clause corresponding to the current sort state.
|
||||
# Use this to sort the controller's table items collection.
|
||||
#
|
||||
def sort_clause()
|
||||
session[@sort_name][:key] + ' ' + (session[@sort_name][:order] || 'ASC')
|
||||
@sort_clause
|
||||
end
|
||||
|
||||
# Returns a link which sorts by the named column.
|
||||
|
||||
@@ -32,9 +32,9 @@
|
||||
<thead><tr>
|
||||
<th><%= l(:field_subject) %></th>
|
||||
<th><%= l(:field_author) %></th>
|
||||
<%= sort_header_tag("#{Message.table_name}.created_on", :caption => l(:field_created_on)) %>
|
||||
<%= sort_header_tag('created_on', :caption => l(:field_created_on)) %>
|
||||
<th><%= l(:label_reply_plural) %></th>
|
||||
<%= sort_header_tag("#{Message.table_name}.updated_on", :caption => l(:label_message_last)) %>
|
||||
<%= sort_header_tag('updated_on', :caption => l(:label_message_last)) %>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
<% @topics.each do |topic| %>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<th><%= link_to image_tag('toggle_check.png'), {}, :onclick => 'toggleIssuesSelection(this.up("form")); return false;',
|
||||
:title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %>
|
||||
</th>
|
||||
<%= sort_header_tag("#{Issue.table_name}.id", :caption => '#', :default_order => 'desc') %>
|
||||
<%= sort_header_tag('id', :caption => '#', :default_order => 'desc') %>
|
||||
<% query.columns.each do |column| %>
|
||||
<%= column_header(column) %>
|
||||
<% end %>
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
<h3><%= l(:label_query_plural) %></h3>
|
||||
|
||||
<% sidebar_queries.each do |query| -%>
|
||||
<%= link_to query.name, :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query %><br />
|
||||
<%= link_to(h(query.name), :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query) %><br />
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<% form_remote_tag(:url => {}, :html => { :id => "journal-#{@journal.id}-form" }) do %>
|
||||
<%= text_area_tag :notes, @journal.notes, :class => 'wiki-edit',
|
||||
:rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min) %>
|
||||
<%= text_area_tag :notes, h(@journal.notes), :class => 'wiki-edit',
|
||||
:rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min) %>
|
||||
<p><%= submit_tag l(:button_save) %>
|
||||
<%= link_to l(:button_cancel), '#', :onclick => "Element.remove('journal-#{@journal.id}-form'); " +
|
||||
"Element.show('journal-#{@journal.id}-notes'); return false;" %></p>
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
<table class="list">
|
||||
<thead><tr>
|
||||
<th><%=l(:field_version)%></th>
|
||||
<%= sort_header_tag("#{Attachment.table_name}.filename", :caption => l(:field_filename)) %>
|
||||
<%= sort_header_tag("#{Attachment.table_name}.created_on", :caption => l(:label_date), :default_order => 'desc') %>
|
||||
<%= sort_header_tag("#{Attachment.table_name}.filesize", :caption => l(:field_filesize), :default_order => 'desc') %>
|
||||
<%= sort_header_tag("#{Attachment.table_name}.downloads", :caption => l(:label_downloads_abbr), :default_order => 'desc') %>
|
||||
<%= sort_header_tag('filename', :caption => l(:field_filename)) %>
|
||||
<%= sort_header_tag('created_on', :caption => l(:label_date), :default_order => 'desc') %>
|
||||
<%= sort_header_tag('size', :caption => l(:field_filesize), :default_order => 'desc') %>
|
||||
<%= sort_header_tag('downloads', :caption => l(:label_downloads_abbr), :default_order => 'desc') %>
|
||||
<th>MD5</th>
|
||||
<% if delete_allowed %><th></th><% end %>
|
||||
</tr></thead>
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<%= sort_header_tag('spent_on', :caption => l(:label_date), :default_order => 'desc') %>
|
||||
<%= sort_header_tag('user_id', :caption => l(:label_member)) %>
|
||||
<%= sort_header_tag('activity_id', :caption => l(:label_activity)) %>
|
||||
<%= sort_header_tag("#{Project.table_name}.name", :caption => l(:label_project)) %>
|
||||
<%= sort_header_tag('issue_id', :caption => l(:label_issue), :default_order => 'desc') %>
|
||||
<%= sort_header_tag('user', :caption => l(:label_member)) %>
|
||||
<%= sort_header_tag('activity', :caption => l(:label_activity)) %>
|
||||
<%= sort_header_tag('project', :caption => l(:label_project)) %>
|
||||
<%= sort_header_tag('issue', :caption => l(:label_issue), :default_order => 'desc') %>
|
||||
<th><%= l(:field_comments) %></th>
|
||||
<%= sort_header_tag('hours', :caption => l(:field_hours)) %>
|
||||
<th></th>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<th class="line-num"><%= line_num %></th>
|
||||
<td class="revision"><%= link_to line[0], :controller => 'wiki', :action => 'index', :id => @project, :page => @page.title, :version => line[0] %></td>
|
||||
<td class="author"><%= h(line[1]) %></td>
|
||||
<td class="line-code"><pre><%= line[2] %></pre></td>
|
||||
<td class="line-code"><pre><%=h line[2] %></pre></td>
|
||||
</tr>
|
||||
<% line_num += 1 %>
|
||||
<% end -%>
|
||||
|
||||
@@ -4,6 +4,11 @@ Redmine - project management software
|
||||
Copyright (C) 2006-2008 Jean-Philippe Lang
|
||||
http://www.redmine.org/
|
||||
|
||||
== 2008-12-30 v0.7.4
|
||||
|
||||
* Fixed several XSS vulnerabilities
|
||||
* Fixed a SQL injection vulnerability
|
||||
|
||||
|
||||
== 2008-07-06 v0.7.3
|
||||
|
||||
|
||||
@@ -433,12 +433,15 @@ class RedCloth < String
|
||||
#
|
||||
# Flexible HTML escaping
|
||||
#
|
||||
def htmlesc( str, mode )
|
||||
def htmlesc( str, mode=:Quotes )
|
||||
if str
|
||||
str.gsub!( '&', '&' )
|
||||
str.gsub!( '"', '"' ) if mode != :NoQuotes
|
||||
str.gsub!( "'", ''' ) if mode == :Quotes
|
||||
str.gsub!( '<', '<')
|
||||
str.gsub!( '>', '>')
|
||||
end
|
||||
str
|
||||
end
|
||||
|
||||
# Search and replace for Textile glyphs (quotes, dashes, other symbols)
|
||||
@@ -462,8 +465,7 @@ class RedCloth < String
|
||||
style << "vertical-align:#{ v_align( $& ) };" if text =~ A_VLGN
|
||||
end
|
||||
|
||||
style << "#{ $1 };" if not filter_styles and
|
||||
text.sub!( /\{([^}]*)\}/, '' )
|
||||
style << "#{ htmlesc $1 };" if text.sub!( /\{([^}]*)\}/, '' ) && !filter_styles
|
||||
|
||||
lang = $1 if
|
||||
text.sub!( /\[([^)]+?)\]/, '' )
|
||||
@@ -783,7 +785,7 @@ class RedCloth < String
|
||||
|
||||
atts = pba( atts )
|
||||
atts = " href=\"#{ url }#{ slash }\"#{ atts }"
|
||||
atts << " title=\"#{ title }\"" if title
|
||||
atts << " title=\"#{ htmlesc title }\"" if title
|
||||
atts = shelve( atts ) if atts
|
||||
|
||||
external = (url =~ /^https?:\/\//) ? ' class="external"' : ''
|
||||
@@ -890,6 +892,7 @@ class RedCloth < String
|
||||
def inline_textile_image( text )
|
||||
text.gsub!( IMAGE_RE ) do |m|
|
||||
stln,algn,atts,url,title,href,href_a1,href_a2 = $~[1..8]
|
||||
htmlesc title
|
||||
atts = pba( atts )
|
||||
atts = " src=\"#{ url }\"#{ atts }"
|
||||
atts << " title=\"#{ title }\"" if title
|
||||
@@ -1027,7 +1030,7 @@ class RedCloth < String
|
||||
else
|
||||
htmlesc( aftertag, :NoQuotes ) if aftertag and not used_offtags['notextile']
|
||||
line = "<redpre##{ @pre_list.length }>"
|
||||
@pre_list << "#{ $3 }#{ aftertag }"
|
||||
@pre_list << "#{ $3.gsub(/<(#{ OFFTAGS })[^>]*>/, '<\\1>') }#{ aftertag }"
|
||||
end
|
||||
elsif $1 and codepre > 0
|
||||
if codepre - used_offtags.length > 0
|
||||
|
||||
@@ -4,7 +4,7 @@ module Redmine
|
||||
module VERSION #:nodoc:
|
||||
MAJOR = 0
|
||||
MINOR = 7
|
||||
TINY = 3
|
||||
TINY = 4
|
||||
|
||||
def self.revision
|
||||
revision = nil
|
||||
|
||||
@@ -32,6 +32,7 @@ module Redmine
|
||||
super
|
||||
self.hard_breaks=true
|
||||
self.no_span_caps=true
|
||||
self.filter_styles=true
|
||||
end
|
||||
|
||||
def to_html(*rules, &block)
|
||||
|
||||
@@ -124,6 +124,16 @@ class IssuesControllerTest < Test::Unit::TestCase
|
||||
assert_equal 'application/pdf', @response.content_type
|
||||
end
|
||||
|
||||
def test_index_sort
|
||||
get :index, :sort_key => 'tracker'
|
||||
assert_response :success
|
||||
|
||||
sort_params = @request.session['issuesindex_sort']
|
||||
assert sort_params.is_a?(Hash)
|
||||
assert_equal 'tracker', sort_params[:key]
|
||||
assert_equal 'ASC', sort_params[:order]
|
||||
end
|
||||
|
||||
def test_changes
|
||||
get :changes, :project_id => 1
|
||||
assert_response :success
|
||||
|
||||
@@ -49,7 +49,10 @@ class ApplicationHelperTest < HelperTestCase
|
||||
'!http://foo.bar/image.jpg!' => '<img src="http://foo.bar/image.jpg" alt="" />',
|
||||
'floating !>http://foo.bar/image.jpg!' => 'floating <div style="float:right"><img src="http://foo.bar/image.jpg" alt="" /></div>',
|
||||
'with class !(some-class)http://foo.bar/image.jpg!' => 'with class <img src="http://foo.bar/image.jpg" class="some-class" alt="" />',
|
||||
'with style !{width:100px;height100px}http://foo.bar/image.jpg!' => 'with style <img src="http://foo.bar/image.jpg" style="width:100px;height100px;" alt="" />',
|
||||
# inline styles should be stripped
|
||||
'with style !{width:100px;height100px}http://foo.bar/image.jpg!' => 'with style <img src="http://foo.bar/image.jpg" alt="" />',
|
||||
'with title !http://foo.bar/image.jpg(This is a title)!' => 'with title <img src="http://foo.bar/image.jpg" title="This is a title" alt="This is a title" />',
|
||||
'with title !http://foo.bar/image.jpg(This is a double-quoted "title")!' => 'with title <img src="http://foo.bar/image.jpg" title="This is a double-quoted "title"" alt="This is a double-quoted "title"" />',
|
||||
}
|
||||
to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
|
||||
end
|
||||
@@ -59,6 +62,7 @@ class ApplicationHelperTest < HelperTestCase
|
||||
'This is a "link":http://foo.bar' => 'This is a <a href="http://foo.bar" class="external">link</a>',
|
||||
'This is an intern "link":/foo/bar' => 'This is an intern <a href="/foo/bar">link</a>',
|
||||
'"link (Link title)":http://foo.bar' => '<a href="http://foo.bar" title="Link title" class="external">link</a>',
|
||||
'"link (Link title with "double-quotes")":http://foo.bar' => '<a href="http://foo.bar" title="Link title with "double-quotes"" class="external">link</a>',
|
||||
# no multiline link text
|
||||
"This is a double quote \"on the first line\nand another on a second line\":test" => "This is a double quote \"on the first line<br />\nand another on a second line\":test"
|
||||
}
|
||||
@@ -146,7 +150,9 @@ class ApplicationHelperTest < HelperTestCase
|
||||
"<pre><code>\nline 1\nline2</code></pre>" => "<pre><code>\nline 1\nline2</code></pre>",
|
||||
"<pre><div>content</div></pre>" => "<pre><div>content</div></pre>",
|
||||
"HTML comment: <!-- no comments -->" => "<p>HTML comment: <!-- no comments --></p>",
|
||||
"<!-- opening comment" => "<p><!-- opening comment</p>"
|
||||
"<!-- opening comment" => "<p><!-- opening comment</p>",
|
||||
# remove attributes
|
||||
"<pre class='foo'>some text</pre>" => "<pre>some text</pre>",
|
||||
}
|
||||
to_test.each { |text, result| assert_equal result, textilizable(text) }
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user