Index: app/controllers/messages_controller.rb =================================================================== --- app/controllers/messages_controller.rb (revision 18419) +++ app/controllers/messages_controller.rb (working copy) @@ -30,22 +30,23 @@ helper :attachments include AttachmentsHelper - REPLIES_PER_PAGE = 25 unless const_defined?(:REPLIES_PER_PAGE) - # Show a topic and its replies def show page = params[:page] # Find the page of the requested reply + replies_order = User.current.wants_comments_in_reverse_order? ? 'DESC' : 'ASC' + @replies = @topic.children. + reorder("#{Message.table_name}.created_on #{replies_order}, #{Message.table_name}.id #{replies_order}") + if params[:r] && page.nil? - offset = @topic.children.where("#{Message.table_name}.id < ?", params[:r].to_i).count - page = 1 + offset / REPLIES_PER_PAGE + offset = @replies.pluck(:id).index(params[:r].to_i) + page = 1 + offset / per_page_option end - @reply_count = @topic.children.count - @reply_pages = Paginator.new @reply_count, REPLIES_PER_PAGE, page - @replies = @topic.children. + @reply_count = @replies.count + @reply_pages = Paginator.new @reply_count, per_page_option, page + @replies = @replies. includes(:author, :attachments, {:board => :project}). - reorder("#{Message.table_name}.created_on ASC, #{Message.table_name}.id ASC"). limit(@reply_pages.per_page). offset(@reply_pages.offset). to_a @@ -107,7 +108,7 @@ @message.destroy flash[:notice] = l(:notice_successful_delete) if @message.parent - redirect_to board_message_path(@board, @message.parent, :r => r) + redirect_to board_message_path(@board, @message.parent) else redirect_to project_board_path(@project, @board) end Index: app/views/messages/_reply_form.html.erb =================================================================== --- app/views/messages/_reply_form.html.erb (nonexistent) +++ app/views/messages/_reply_form.html.erb (working copy) @@ -0,0 +1,14 @@ +<% has_form ||= false %> +<% if !@topic.locked? && authorize_for('messages', 'reply') %> +<% if has_form %> +

<%= toggle_link l(:button_reply), "reply", :focus => 'message_content' %>

+ +<% else %> +

<%= toggle_link l(:button_reply), "reply", :focus => 'message_content', :scroll => 'message_content' %>

+<% end %> +<% end %> Index: app/views/messages/show.html.erb =================================================================== --- app/views/messages/show.html.erb (revision 18419) +++ app/views/messages/show.html.erb (working copy) @@ -36,9 +36,7 @@ <% unless @replies.empty? %>

<%= l(:label_reply_plural) %> (<%= @reply_count %>)

-<% if !@topic.locked? && authorize_for('messages', 'reply') && @replies.size >= 3 %> -

<%= toggle_link l(:button_reply), "reply", :focus => 'message_content', :scroll => "message_content" %>

-<% end %> +<%= render :partial => 'reply_form', :locals => {:has_form => User.current.wants_comments_in_reverse_order? } %> <% @replies.each do |message| %>
">
@@ -76,17 +74,9 @@
<% end %>
-<%= pagination_links_full @reply_pages, @reply_count, :per_page_links => false %> +<%= pagination_links_full @reply_pages, @reply_count %> <% end %> -<% if !@topic.locked? && authorize_for('messages', 'reply') %> -

<%= toggle_link l(:button_reply), "reply", :focus => 'message_content' %>

- -<% end %> +<%= render :partial => 'reply_form', :locals => {:has_form => @replies.empty? || !User.current.wants_comments_in_reverse_order? } %> <% html_title @topic.subject %> Index: test/functional/messages_controller_test.rb =================================================================== --- test/functional/messages_controller_test.rb (revision 18419) +++ test/functional/messages_controller_test.rb (working copy) @@ -252,7 +252,7 @@ :id => 2 } end - assert_redirected_to '/boards/1/topics/1?r=2' + assert_redirected_to '/boards/1/topics/1' assert_equal I18n.t(:notice_successful_delete), flash[:notice] assert_nil Message.find_by_id(2) end Index: test/integration/messages_test.rb =================================================================== --- test/integration/messages_test.rb (nonexistent) +++ test/integration/messages_test.rb (working copy) @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +# Redmine - project management software +# Copyright (C) 2006-2019 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.expand_path('../../test_helper', __FILE__) + +class MessagesTest < Redmine::IntegrationTest + fixtures :projects, :users, :email_addresses, :user_preferences, :members, + :member_roles, :roles, :boards, :messages, :enabled_modules + + def setup + message = Message.find(1) + assert_difference 'Message.count', 60 do + 60.times do + message.children << Message.new( + :subject => 'Reply', + :content => 'Reply body', + :author_id => 2, + :board_id => 1) + end + end + @reply_ids = message.children.map(&:id).sort + @per_page = (@reply_ids.count - 1).to_s + + log_user('jsmith', 'jsmith') + end + + def test_show_with_pagination_should_ascending_order + with_settings :per_page_options => @per_page do + put '/my/account', :params => { :pref => { :comments_sorting => 'asc' }} + assert !User.current.wants_comments_in_reverse_order? + + get '/boards/1/topics/1', :params => { :r => @reply_ids.last } + assert_select 'span.pagination > ul.pages > li.current > span', text: '2' + end + end + + def test_show_with_pagination_should_descending_order + with_settings :per_page_options => @per_page do + put '/my/account', :params => { :pref => { :comments_sorting => 'desc' }} + assert User.current.wants_comments_in_reverse_order? + + get '/boards/1/topics/1', :params => { :r => @reply_ids.last } + assert_select 'span.pagination > ul.pages > li.current > span', text: '1' + end + end + +end +require File.expand_path('../../test_helper', __FILE__) + +class MessagesTest < Redmine::IntegrationTest + fixtures :projects, :users, :email_addresses, :user_preferences, :members, + :member_roles, :roles, :boards, :messages, :enabled_modules + + def setup + message = Message.find(1) + assert_difference 'Message.count', 60 do + 60.times do + message.children << Message.new( + :subject => 'Reply', + :content => 'Reply body', + :author_id => 2, + :board_id => 1) + end + end + @reply_ids = message.children.map(&:id).sort + @per_page = (@reply_ids.count - 1).to_s + + log_user('jsmith', 'jsmith') + end + + def test_show_with_pagination_should_ascending_order + with_settings :per_page_options => @per_page do + put '/my/account', :params => { :pref => { :comments_sorting => 'asc' }} + assert !User.current.wants_comments_in_reverse_order? + + get '/boards/1/topics/1', :params => { :r => @reply_ids.last } + assert_select 'span.pagination > ul.pages > li.current > span', text: '2' + end + end + + def test_show_with_pagination_should_descending_order + with_settings :per_page_options => @per_page do + put '/my/account', :params => { :pref => { :comments_sorting => 'desc' }} + assert User.current.wants_comments_in_reverse_order? + + get '/boards/1/topics/1', :params => { :r => @reply_ids.last } + assert_select 'span.pagination > ul.pages > li.current > span', text: '1' + end + end + +end